Line data Source code
1 : /*
2 : * vr_nexthop.c -- data path nexthop management
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : */
6 : #include <vr_os.h>
7 : #include <vr_types.h>
8 : #include <vr_packet.h>
9 : #include <vr_interface.h>
10 : #include <vr_nexthop.h>
11 : #include <vr_vxlan.h>
12 :
13 : #include "vr_message.h"
14 : #include "vr_sandesh.h"
15 : #include "vr_bridge.h"
16 : #include "vr_btable.h"
17 : #include "vr_datapath.h"
18 : #include "vr_route.h"
19 : #include "vr_hash.h"
20 : #include "vr_mirror.h"
21 : #include "vr_offloads_dp.h"
22 :
23 : extern bool vr_has_to_fragment(struct vr_interface *, struct vr_packet *,
24 : unsigned int);
25 : extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short, unsigned int);
26 : extern struct vr_nexthop *vr_inet6_ip_lookup(unsigned short, uint8_t *);
27 : extern struct vr_nexthop *vr_inet_ip_lookup(unsigned short, uint32_t);
28 : extern struct vr_nexthop *vr_inet_src_lookup(unsigned short,
29 : struct vr_packet *);
30 : extern l4_pkt_type_t vr_ip6_well_known_packet(struct vr_packet *);
31 : extern l4_pkt_type_t vr_ip_well_known_packet(struct vr_packet *);
32 :
33 :
34 : struct vr_nexthop *ip4_default_nh;
35 : struct vr_nexthop *ip6_default_nh;
36 :
37 : unsigned int vr_nexthops = VR_DEF_NEXTHOPS;
38 :
39 : struct vr_nexthop *
40 27894586 : __vrouter_get_nexthop(struct vrouter *router, unsigned int index)
41 : {
42 27894586 : if (!router || index >= router->vr_max_nexthops)
43 0 : return NULL;
44 :
45 27894586 : return *(struct vr_nexthop **)vr_btable_get(router->vr_nexthops, index);
46 : }
47 :
48 : struct vr_nexthop *
49 106621 : vrouter_get_nexthop(unsigned int rid, unsigned int index)
50 : {
51 : struct vr_nexthop *nh;
52 : struct vrouter *router;
53 :
54 106621 : router = vrouter_get(rid);
55 106621 : nh = __vrouter_get_nexthop(router, index);
56 106621 : if (nh)
57 106237 : (void)vr_sync_add_and_fetch_32u(&nh->nh_users, 1);
58 :
59 106621 : return nh;
60 : }
61 :
62 : static int
63 635 : __vrouter_set_nexthop(struct vrouter *router, unsigned int index,
64 : struct vr_nexthop *nh)
65 : {
66 : struct vr_nexthop **nh_p;
67 :
68 635 : nh_p = (struct vr_nexthop **)vr_btable_get(router->vr_nexthops, index);
69 635 : if (!nh_p)
70 0 : return -EINVAL;
71 :
72 635 : *nh_p = nh;
73 635 : return 0;
74 : }
75 :
76 : static bool
77 2 : vr_l2_control_data_add(struct vr_packet **pkt)
78 : {
79 :
80 : unsigned int *data;
81 : struct vr_packet *tmp_pkt;
82 :
83 2 : if (pkt_head_space(*pkt) < VR_L2_CTRL_DATA_LEN) {
84 0 : tmp_pkt = vr_pexpand_head(*pkt, VR_L2_CTRL_DATA_LEN -
85 0 : pkt_head_space(*pkt));
86 0 : if (!tmp_pkt)
87 0 : return false;
88 0 : *pkt = tmp_pkt;
89 : }
90 :
91 2 : data = (unsigned int *)pkt_push(*pkt, VR_L2_CTRL_DATA_LEN);
92 2 : if (!data)
93 0 : return false;
94 :
95 2 : *data = VR_L2_CTRL_DATA;
96 2 : return true;
97 : }
98 :
99 :
100 : static void
101 309 : vrouter_free_nexthop(struct vr_nexthop *nh)
102 : {
103 : int i;
104 :
105 309 : if (nh->nh_type == NH_COMPOSITE) {
106 5 : if (nh->nh_component_nh) {
107 5 : vr_free(nh->nh_component_nh, VR_NEXTHOP_COMPONENT_OBJECT);
108 5 : nh->nh_component_nh = NULL;
109 : }
110 :
111 5 : if (nh->nh_component_ecmp) {
112 4 : nh->nh_component_ecmp_cnt = 0;
113 4 : vr_free(nh->nh_component_ecmp, VR_NEXTHOP_COMPONENT_OBJECT);
114 4 : nh->nh_component_ecmp = NULL;
115 : }
116 :
117 304 : } else if ((nh->nh_type == NH_TUNNEL) &&
118 52 : (nh->nh_flags & NH_FLAG_TUNNEL_UDP) &&
119 1 : (nh->nh_family == AF_INET6)) {
120 0 : if (nh->nh_udp_tun6_sip) {
121 0 : vr_free(nh->nh_udp_tun6_sip, VR_NETWORK_ADDRESS_OBJECT);
122 0 : nh->nh_udp_tun6_sip = NULL;
123 : }
124 :
125 0 : if (nh->nh_udp_tun6_dip) {
126 0 : vr_free(nh->nh_udp_tun6_dip, VR_NETWORK_ADDRESS_OBJECT);
127 0 : nh->nh_udp_tun6_dip = NULL;
128 : }
129 : }
130 :
131 1236 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
132 927 : if (nh->nh_dev_arr[i]) {
133 237 : vrouter_put_interface(nh->nh_dev_arr[i]);
134 : }
135 : }
136 :
137 309 : vr_free(nh, VR_NEXTHOP_OBJECT);
138 309 : return;
139 : }
140 :
141 : static void
142 179 : vrouter_free_nexthop_cb(struct vrouter *router, void *data)
143 : {
144 179 : struct vr_defer_data *vdd = (struct vr_defer_data *)data;
145 :
146 179 : if (!vdd)
147 0 : return;
148 :
149 179 : vrouter_free_nexthop((struct vr_nexthop *)vdd->vdd_data);
150 179 : return;
151 : }
152 :
153 : static int
154 179 : vrouter_free_nexthop_defer(struct vr_nexthop *nh)
155 : {
156 : struct vr_defer_data *defer;
157 :
158 179 : defer = vr_get_defer_data(sizeof(*defer));
159 179 : if (!defer)
160 0 : return -ENOMEM;
161 :
162 179 : defer->vdd_data = nh;
163 179 : vr_defer(nh->nh_router, vrouter_free_nexthop_cb, (void *)defer);
164 :
165 179 : return 0;
166 : }
167 :
168 : void
169 106543 : vrouter_put_nexthop(struct vr_nexthop *nh)
170 : {
171 : int i, component_cnt;
172 : struct vr_nexthop *cnh;
173 : unsigned int ref_cnt;
174 :
175 106543 : if (!nh)
176 0 : return;
177 :
178 : /* This function might get invoked with zero ref_cnt */
179 106543 : ref_cnt = nh->nh_users;
180 106543 : if (ref_cnt) {
181 106542 : ref_cnt = vr_sync_sub_and_fetch_32u(&nh->nh_users, 1);
182 : }
183 :
184 106543 : if (!ref_cnt ) {
185 :
186 : /* If indirect, lets de-ref the direct nh too */
187 309 : if ((nh->nh_flags & NH_FLAG_INDIRECT) && nh->nh_direct_nh) {
188 0 : cnh = nh->nh_direct_nh;
189 0 : nh->nh_direct_nh = NULL;
190 0 : vrouter_put_nexthop(cnh);
191 : }
192 :
193 : /* If composite de-ref the internal nexthops */
194 309 : if (nh->nh_type == NH_COMPOSITE) {
195 5 : component_cnt = nh->nh_component_cnt;
196 5 : nh->nh_component_cnt = 0;
197 14 : for (i = 0; i < component_cnt; i++) {
198 9 : if (nh->nh_component_nh[i].cnh) {
199 9 : cnh = nh->nh_component_nh[i].cnh;
200 9 : nh->nh_component_nh[i].cnh = NULL;
201 9 : vrouter_put_nexthop(cnh);
202 : }
203 : }
204 : }
205 :
206 309 : if (vr_not_ready) {
207 130 : vrouter_free_nexthop(nh);
208 : } else {
209 179 : if (vrouter_free_nexthop_defer(nh)) {
210 0 : vr_delay_op();
211 0 : vrouter_free_nexthop(nh);
212 : }
213 : }
214 : }
215 :
216 106543 : return;
217 : }
218 :
219 : static int
220 329 : vrouter_add_nexthop(struct vr_nexthop *nh)
221 : {
222 329 : struct vrouter *router = vrouter_get(nh->nh_rid);
223 :
224 329 : if (!router || nh->nh_id >= router->vr_max_nexthops)
225 0 : return -EINVAL;
226 :
227 : /*
228 : * NH change just copies the field
229 : * over to nexthop, incase of change
230 : * just return
231 : */
232 329 : if (__vrouter_get_nexthop(router, nh->nh_id))
233 12 : return 0;
234 :
235 317 : nh->nh_users++;
236 317 : return __vrouter_set_nexthop(router, nh->nh_id, nh);
237 : }
238 :
239 : static void
240 318 : nh_del(struct vr_nexthop *nh)
241 : {
242 318 : struct vrouter *router = vrouter_get(nh->nh_rid);
243 :
244 318 : if (!router || nh->nh_id >= router->vr_max_nexthops)
245 0 : return;
246 :
247 318 : __vrouter_set_nexthop(router, nh->nh_id, NULL);
248 318 : vrouter_put_nexthop(nh);
249 :
250 318 : return;
251 : }
252 :
253 : bool
254 44 : vr_gateway_nexthop(struct vr_nexthop *nh)
255 : {
256 44 : if (nh) {
257 44 : if (!nh->nh_dev)
258 2 : return false;
259 :
260 42 : if ((nh->nh_type == NH_ENCAP) &&
261 27 : (nh->nh_dev->vif_type == VIF_TYPE_AGENT))
262 0 : return true;
263 : }
264 :
265 42 : return false;
266 : }
267 :
268 :
269 : bool
270 0 : vr_hosted_nexthop(struct vr_nexthop *nh)
271 : {
272 0 : if (nh) {
273 0 : if (!nh->nh_dev)
274 0 : return false;
275 :
276 0 : if ((nh->nh_type == NH_ENCAP) && vif_is_virtual(nh->nh_dev))
277 0 : return true;
278 : }
279 :
280 0 : return false;
281 : }
282 :
283 : static int
284 63 : nh_tunnel_loop_detect_handle(struct vr_packet *pkt, struct vr_nexthop *nh,
285 : struct vr_forwarding_md *fmd, uint32_t dip)
286 : {
287 63 : if (!pkt || !nh || !fmd || !dip)
288 0 : return 0;
289 :
290 63 : if ((!fmd->fmd_outer_src_ip) || !vif_is_fabric(pkt->vp_if))
291 63 : return 0;
292 :
293 0 : if (nh->nh_type != NH_TUNNEL)
294 0 : return 0;
295 :
296 0 : if (fmd->fmd_outer_src_ip == dip) {
297 0 : PKT_LOG(VP_DROP_PKT_LOOP, pkt, 0, VR_NEXTHOP_C, __LINE__);
298 0 : vr_pfree(pkt, VP_DROP_PKT_LOOP);
299 0 : return 1;
300 : }
301 :
302 0 : return 0;
303 : }
304 :
305 : static struct vr_interface *
306 8 : nh_underlay_tunnel_vif_selection(struct vr_packet *pkt, struct
307 : vr_forwarding_md *fmd, struct vr_nexthop *nh, unsigned short *drop_reason)
308 : {
309 8 : struct vr_interface *vif = NULL;
310 : uint32_t hash;
311 : int index;
312 :
313 : /* flow mode: check for underlay ecmp index */
314 8 : if (fmd->fmd_underlay_ecmp_index >= 0) {
315 : /* If true, then assign that index to vif */
316 1 : if (nh->nh_encap_valid[fmd->fmd_underlay_ecmp_index])
317 1 : vif = nh->nh_dev_arr[fmd->fmd_underlay_ecmp_index];
318 : else {
319 0 : *drop_reason = VP_DROP_INVALID_UNDERLAY_ECMP;
320 0 : return vif;
321 : }
322 : } else {
323 : /* packet mode: compute 5 tuple hash and assign interface */
324 7 : hash = vr_get_pkt_hash(pkt);
325 7 : index = hash % VR_MAX_PHY_INF;
326 7 : if (!nh->nh_encap_valid[index]) {
327 4 : if (!nh->nh_valid_underlay_dev_count) {
328 0 : *drop_reason = VP_DROP_INVALID_UNDERLAY_ECMP;
329 0 : return vif;
330 : }
331 4 : hash = hash % nh->nh_valid_underlay_dev_count;
332 4 : vif = nh->nh_valid_underlay_dev[hash];
333 : } else
334 3 : vif = nh->nh_dev_arr[index];
335 : }
336 :
337 8 : return vif;
338 : }
339 :
340 :
341 : static nh_processing_t
342 0 : nh_resolve(struct vr_packet *pkt, struct vr_nexthop *nh,
343 : struct vr_forwarding_md *fmd)
344 : {
345 0 : struct vr_vrf_stats *stats = NULL;
346 : struct vr_packet *pkt_clone;
347 :
348 0 : if (vr_inet_vrf_stats) {
349 0 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
350 0 : if (stats)
351 0 : stats->vrf_resolves++;
352 : }
353 :
354 : /*
355 : * bridge is set only for vhost/physical interface, and this
356 : * path will be hit only for packets from vhost, in which case
357 : * we already know everything that has to be known i.e. we know
358 : * the outgoing device and the mac address (which was already
359 : * resolved as part of the arp request from host
360 : */
361 0 : pkt_clone = vr_pclone(pkt);
362 0 : if (pkt_clone) {
363 : /* xconnect the original pkt */
364 0 : vr_preset(pkt);
365 0 : vif_xconnect(pkt->vp_if, pkt, fmd);
366 : /* will trap the packet to agent to create a route */
367 0 : vr_trap(pkt_clone, fmd->fmd_dvrf, AGENT_TRAP_RESOLVE, NULL);
368 0 : return NH_PROCESSING_COMPLETE;
369 : }
370 :
371 : /* will trap the packet to agent to create a route */
372 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_RESOLVE, NULL);
373 :
374 0 : return NH_PROCESSING_COMPLETE;
375 : }
376 :
377 : static nh_processing_t
378 1 : nh_vrf_translate(struct vr_packet *pkt, struct vr_nexthop *nh,
379 : struct vr_forwarding_md *fmd)
380 : {
381 1 : struct vr_vrf_stats *stats = NULL;
382 :
383 1 : if (vr_inet_vrf_stats) {
384 1 : stats = vr_inet_vrf_stats(nh->nh_vrf, pkt->vp_cpu);
385 1 : if (stats)
386 1 : stats->vrf_vrf_translates++;
387 : }
388 :
389 1 : fmd->fmd_dvrf = nh->nh_vrf;
390 1 : if (nh->nh_family == AF_INET)
391 0 : return vr_forward(nh->nh_router, pkt, fmd);
392 :
393 1 : if (pkt->vp_type == VP_TYPE_PBB) {
394 0 : if (vr_pbb_decode(pkt, fmd))
395 0 : return 0;
396 : }
397 :
398 1 : vr_bridge_input(nh->nh_router, pkt, fmd);
399 :
400 1 : return NH_PROCESSING_COMPLETE;
401 : }
402 :
403 : static nh_processing_t
404 29 : nh_l2_rcv(struct vr_packet *pkt, struct vr_nexthop *nh,
405 : struct vr_forwarding_md *fmd)
406 : {
407 : unsigned char eth_dmac[VR_ETHER_ALEN], *data;
408 29 : int pull_len, handled = 0;
409 29 : struct vr_vrf_stats *stats = NULL;
410 :
411 29 : if (vr_inet_vrf_stats) {
412 29 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
413 29 : if (stats)
414 29 : stats->vrf_l2_receives++;
415 : }
416 :
417 29 : data = pkt_data(pkt);
418 29 : fmd->fmd_to_me = 1;
419 29 : pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
420 29 : if (!pkt_pull(pkt, pull_len)) {
421 0 : PKT_LOG(VP_DROP_PULL, pkt, 0, VR_NEXTHOP_C, __LINE__);
422 0 : vr_pfree(pkt, VP_DROP_PULL);
423 0 : return NH_PROCESSING_COMPLETE;
424 : }
425 :
426 : /*
427 : * there should not be any unicast ARP requests destined to "my mac".
428 : * The ARP response destined to "my mac" incase of ARP request being
429 : * generated by Agent for some features
430 : */
431 29 : if (pkt->vp_type == VP_TYPE_IP6) {
432 0 : VR_MAC_COPY(eth_dmac, data);
433 0 : handled = vr_neighbor_input(pkt, fmd, eth_dmac);
434 0 : if (!handled)
435 0 : handled = vr_l3_input(pkt, fmd);
436 29 : } else if (pkt->vp_type == VP_TYPE_IP) {
437 29 : handled = vr_l3_input(pkt, fmd);
438 0 : } else if (pkt->vp_type == VP_TYPE_ARP) {
439 0 : VR_MAC_COPY(eth_dmac, data);
440 0 : handled = vr_arp_input(pkt, fmd, eth_dmac);
441 : }
442 :
443 29 : if (!handled){
444 0 : PKT_LOG(VP_DROP_INVALID_PROTOCOL, pkt, 0, VR_NEXTHOP_C, __LINE__);
445 0 : vr_pfree(pkt, VP_DROP_INVALID_PROTOCOL);
446 : }
447 29 : return NH_PROCESSING_COMPLETE;
448 : }
449 :
450 : static nh_processing_t
451 11 : nh_l3_rcv(struct vr_packet *pkt, struct vr_nexthop *nh,
452 : struct vr_forwarding_md *fmd)
453 : {
454 11 : struct vr_vrf_stats *stats = NULL;
455 :
456 11 : if (vr_inet_vrf_stats) {
457 11 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
458 11 : if (stats)
459 11 : stats->vrf_receives++;
460 : }
461 :
462 11 : if (nh->nh_family == AF_INET)
463 11 : return vr_ip_rcv(nh->nh_router, pkt, fmd);
464 : else {
465 0 : PKT_LOG(VP_DROP_INVALID_PROTOCOL, pkt, 0, VR_NEXTHOP_C, __LINE__);
466 0 : vr_pfree(pkt, VP_DROP_INVALID_PROTOCOL);
467 : }
468 0 : return NH_PROCESSING_COMPLETE;
469 : }
470 :
471 : static int
472 57 : nh_push_mpls_header(struct vr_packet *pkt, unsigned int label,
473 : struct vr_forwarding_class_qos *qos, bool is_bottom_label)
474 : {
475 57 : uint32_t exp_qos = 0;
476 : unsigned int *lbl;
477 : unsigned int ttl;
478 57 : unsigned int label_pos = 0;
479 :
480 57 : lbl = (unsigned int *)pkt_push(pkt, sizeof(unsigned int));
481 57 : if (!lbl)
482 0 : return -ENOSPC;
483 :
484 : /* Use the ttl from packet. If not ttl,
485 : * initialise to some arbitrary value */
486 57 : ttl = pkt->vp_ttl;
487 57 : if (!ttl) {
488 0 : ttl = 64;
489 : }
490 :
491 57 : if (qos) {
492 0 : exp_qos = qos->vfcq_mpls_qos;
493 0 : exp_qos <<= VR_MPLS_EXP_QOS_SHIFT;
494 : }
495 57 : if (is_bottom_label) {
496 57 : label_pos = 1;
497 : }
498 57 : *lbl = htonl((label << VR_MPLS_LABEL_SHIFT) | exp_qos |
499 57 : (label_pos << 8) | ttl);
500 :
501 57 : return 0;
502 : }
503 :
504 : /*
505 : * nh_udp_tunnel_helper - helper function to use for UDP tunneling. Used
506 : * by mirroring and MPLS over UDP. Returns true on success, false otherwise.
507 : */
508 : static bool
509 60 : nh_udp_tunnel_helper(struct vr_packet *pkt, unsigned short sport,
510 : unsigned short dport, unsigned int sip,
511 : unsigned int dip, struct vr_forwarding_class_qos *qos)
512 : {
513 : struct vr_ip *ip;
514 : struct vr_udp *udp;
515 :
516 : /* Udp Header */
517 60 : udp = (struct vr_udp *)pkt_push(pkt, sizeof(struct vr_udp));
518 60 : if (!udp) {
519 0 : return false;
520 : }
521 :
522 60 : udp->udp_sport = sport;
523 60 : udp->udp_dport = dport;
524 60 : udp->udp_length = htons(pkt_len(pkt));
525 60 : udp->udp_csum = 0;
526 :
527 : /* And now the IP header */
528 60 : ip = (struct vr_ip *)pkt_push(pkt, sizeof(struct vr_ip));
529 60 : if (!ip) {
530 0 : return false;
531 : }
532 :
533 60 : ip->ip_version = 4;
534 60 : ip->ip_hl = 5;
535 60 : if (qos) {
536 0 : ip->ip_tos = VR_IP_DSCP(qos->vfcq_dscp);
537 0 : pkt->vp_queue = qos->vfcq_queue_id;
538 0 : pkt->vp_priority = qos->vfcq_dotonep_qos;
539 : } else {
540 60 : ip->ip_tos = 0;
541 : }
542 60 : ip->ip_id = htons(vr_generate_unique_ip_id());
543 60 : ip->ip_frag_off = 0;
544 :
545 60 : if (vr_pkt_is_diag(pkt)) {
546 0 : ip->ip_ttl = pkt->vp_ttl;
547 : } else {
548 60 : ip->ip_ttl = 64;
549 : }
550 :
551 60 : ip->ip_proto = VR_IP_PROTO_UDP;
552 60 : ip->ip_saddr = sip;
553 60 : ip->ip_daddr = dip;
554 60 : ip->ip_len = htons(pkt_len(pkt));
555 :
556 : /*
557 : * header checksum
558 : */
559 60 : ip->ip_csum = 0;
560 60 : ip->ip_csum = vr_ip_csum(ip);
561 :
562 60 : return true;
563 : }
564 :
565 : static bool
566 0 : nh_udp_tunnel6_helper(struct vr_packet *pkt, struct vr_nexthop *nh,
567 : uint8_t *sip, uint16_t sport, uint16_t dport)
568 : {
569 : struct vr_ip6 *ip6;
570 : struct vr_udp *udp;
571 :
572 0 : if (!sip)
573 0 : sip = nh->nh_udp_tun6_sip;
574 :
575 : /* udp Header */
576 0 : udp = (struct vr_udp *)pkt_push(pkt, sizeof(struct vr_udp));
577 0 : if (!udp) {
578 0 : return false;
579 : }
580 :
581 0 : udp->udp_sport = sport;
582 0 : udp->udp_dport = dport;
583 0 : udp->udp_length = htons(pkt_len(pkt));
584 0 : udp->udp_csum = 0;
585 :
586 : /* And now the IP6 header */
587 0 : ip6 = (struct vr_ip6 *)pkt_push(pkt, sizeof(struct vr_ip6));
588 0 : if (!ip6) {
589 0 : return false;
590 : }
591 :
592 0 : ip6->ip6_version = 6;
593 0 : ip6->ip6_priority_l = 0;
594 0 : ip6->ip6_priority_h = 0;
595 0 : ip6->ip6_flow_l = 0;
596 0 : ip6->ip6_flow_h = 0;
597 0 : ip6->ip6_plen = htons(pkt_len(pkt) - sizeof(struct vr_ip6));
598 0 : ip6->ip6_nxt = VR_IP_PROTO_UDP;
599 0 : ip6->ip6_hlim = 64;
600 :
601 0 : memcpy(ip6->ip6_src, sip, VR_IP6_ADDRESS_LEN);
602 0 : memcpy(ip6->ip6_dst, nh->nh_udp_tun6_dip, VR_IP6_ADDRESS_LEN);
603 :
604 :
605 0 : return true;
606 : }
607 :
608 : static bool
609 0 : nh_pbb_tunnel_helper(struct vrouter *router, struct vr_packet **pkt,
610 : struct vr_forwarding_md *fmd, uint8_t *dmac, uint8_t *smac,
611 : uint32_t isid)
612 : {
613 : int pbb_head_space;
614 : struct vr_pbb_itag *pbb_itag;
615 : struct vr_eth *eth;
616 : struct vr_packet *expanded_pkt;
617 :
618 0 : pbb_head_space = sizeof(struct vr_pbb_itag) + VR_ETHER_HLEN;
619 :
620 0 : if (pkt_head_space(*pkt) < pbb_head_space) {
621 0 : expanded_pkt = vr_pexpand_head(*pkt, pbb_head_space - pkt_head_space(*pkt));
622 0 : if (!expanded_pkt)
623 0 : return false;
624 0 : *pkt = expanded_pkt;
625 : }
626 :
627 0 : pbb_itag = (struct vr_pbb_itag *)pkt_push(*pkt, sizeof(*pbb_itag));
628 0 : if (!pbb_itag)
629 0 : return false;
630 0 : pbb_itag->pbbi_pcp = pbb_itag->pbbi_dei = 0;
631 0 : pbb_itag->pbbi_uca = pbb_itag->pbbi_res = 0;
632 0 : pbb_itag->pbbi_isid = (htonl(isid) >> 8) & 0xFFFFFF;
633 :
634 0 : eth = (struct vr_eth *)pkt_push(*pkt, VR_ETHER_HLEN);
635 0 : if(!eth)
636 0 : return false;
637 :
638 0 : VR_MAC_COPY(eth->eth_dmac, dmac);
639 0 : VR_MAC_COPY(eth->eth_smac, smac);
640 0 : eth->eth_proto = htons(VR_ETH_PROTO_PBB);
641 :
642 0 : return true;
643 : }
644 :
645 : static bool
646 8 : nh_vxlan_tunnel_helper(struct vrouter *router, struct vr_packet **pkt,
647 : struct vr_forwarding_md *fmd, unsigned int sip, unsigned int dip)
648 : {
649 8 : unsigned short udp_src_port = VR_VXLAN_UDP_SRC_PORT;
650 :
651 : struct vr_vxlan *vxlanh;
652 : struct vr_packet *expanded_pkt;
653 : struct vr_forwarding_class_qos *qos;
654 :
655 8 : if (pkt_head_space(*pkt) < VR_VXLAN_HDR_LEN) {
656 0 : expanded_pkt = vr_pexpand_head(*pkt, VR_VXLAN_HDR_LEN - pkt_head_space(*pkt));
657 0 : if (!expanded_pkt) {
658 0 : return false;
659 : }
660 0 : *pkt = expanded_pkt;
661 : }
662 :
663 8 : if (fmd->fmd_udp_src_port)
664 2 : udp_src_port = fmd->fmd_udp_src_port;
665 :
666 : /*
667 : * The UDP source port is a hash of the inner headers
668 : */
669 8 : if ((!fmd->fmd_udp_src_port) && vr_get_udp_src_port) {
670 6 : udp_src_port = vr_get_udp_src_port(*pkt, fmd, fmd->fmd_dvrf);
671 6 : if (udp_src_port == 0) {
672 0 : return false;
673 : }
674 : }
675 :
676 8 : vr_fmd_update_label_type(fmd, VR_LABEL_TYPE_VXLAN_ID);
677 :
678 : /* Add the vxlan header */
679 8 : vxlanh = (struct vr_vxlan *)pkt_push(*pkt, sizeof(struct vr_vxlan));
680 8 : vxlanh->vxlan_vnid = htonl(fmd->fmd_label << VR_VXLAN_VNID_SHIFT);
681 8 : vxlanh->vxlan_flags = htonl(VR_VXLAN_IBIT);
682 :
683 8 : qos = vr_qos_get_forwarding_class(router, *pkt, fmd);
684 8 : return nh_udp_tunnel_helper(*pkt, htons(udp_src_port),
685 8 : htons(VR_VXLAN_UDP_DST_PORT), sip, dip, qos);
686 : }
687 :
688 : static struct vr_packet *
689 2 : nh_mcast_clone(struct vr_packet *pkt, unsigned short head_room)
690 : {
691 : struct vr_packet *clone_pkt;
692 :
693 : /* Clone the packet */
694 2 : clone_pkt = vr_pclone(pkt);
695 2 : if (!clone_pkt) {
696 0 : return NULL;
697 : }
698 :
699 : /* Increase the head space by the head_room */
700 2 : if (vr_pcow(&clone_pkt, head_room)) {
701 0 : PKT_LOG(VP_DROP_PCOW_FAIL, pkt, 0, VR_NEXTHOP_C, __LINE__);
702 0 : vr_pfree(clone_pkt, VP_DROP_PCOW_FAIL);
703 0 : return NULL;
704 : }
705 :
706 : /* Copy the ttl from old packet */
707 2 : clone_pkt->vp_ttl = pkt->vp_ttl;
708 :
709 2 : return clone_pkt;
710 : }
711 :
712 : static int
713 0 : nh_composite_ecmp_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
714 : struct vr_forwarding_md *fmd, void *ret_data)
715 : {
716 : int i;
717 0 : int status = NH_SOURCE_INVALID;
718 0 : unsigned int inner_ecmp_index = -1;/* reset to invalid */
719 0 : struct vr_nexthop *cnh = NULL;
720 :
721 : /* the first few checks are straight forward */
722 0 : if (!fmd)
723 0 : return NH_SOURCE_INVALID;
724 :
725 0 : if ((fmd->fmd_ecmp_src_nh_index >= 0) &&
726 0 : (fmd->fmd_ecmp_src_nh_index < nh->nh_component_cnt)) {
727 0 : cnh = nh->nh_component_nh[fmd->fmd_ecmp_src_nh_index].cnh;
728 : }
729 :
730 : /*
731 : * when the 'supposed' source goes down, cnh is null, in which
732 : * case validate the source against other present nexthops. follow
733 : * the same logic if the component validate source returns invalid
734 : * source, which could mean that source has moved
735 : */
736 0 : if (!cnh || (!cnh->nh_validate_src) ||
737 0 : (NH_SOURCE_INVALID == cnh->nh_validate_src(pkt, cnh, fmd, NULL))) {
738 0 : for (i = 0; i < nh->nh_component_cnt; i++) {
739 0 : if (i == fmd->fmd_ecmp_src_nh_index)
740 0 : continue;
741 :
742 0 : cnh = nh->nh_component_nh[i].cnh;
743 : /* If direct nexthop is not valid, dont process it */
744 0 : if (!cnh || !(cnh->nh_flags & NH_FLAG_VALID) ||
745 0 : !cnh->nh_validate_src)
746 0 : continue;
747 :
748 : /*
749 : * if the source has moved to a present and valid source,
750 : * return mismatch
751 : */
752 0 : status = cnh->nh_validate_src(pkt, cnh, fmd, &inner_ecmp_index);
753 0 : if (status == NH_SOURCE_VALID) {
754 0 : if (ret_data) {
755 0 : *(unsigned int *)ret_data = i;
756 : }
757 0 : return NH_SOURCE_MISMATCH;
758 : }
759 : /*
760 : * Handle multi level ECMP,
761 : * inner ecmp returns NH_SOURCE_MISMATCH, return the
762 : * same error. copy inner_ecmp_value for NH mismatch case only.
763 : */
764 0 : if (status == NH_SOURCE_MISMATCH) {
765 0 : if (ret_data) {
766 0 : *(unsigned int *)ret_data = inner_ecmp_index;
767 : }
768 0 : return NH_SOURCE_MISMATCH;
769 : }
770 : }
771 :
772 : /* if everything else fails, source is indeed invalid */
773 0 : return NH_SOURCE_INVALID;
774 : }
775 :
776 : /* source is validated by validate_src */
777 0 : return NH_SOURCE_VALID;
778 : }
779 :
780 : /*
781 : * nh_ecmp_config_hash is two byte value. The configurable hash as such is
782 : * 5 bit field. We store agent added configurable hash values in the first
783 : * byte and convert them to Flow flags and store them in second byte
784 : */
785 : static void
786 4 : nh_ecmp_store_ecmp_config_hash(vr_nexthop_req *req, struct vr_nexthop *nh)
787 : {
788 : unsigned char hash;
789 : unsigned short flow_hash;
790 : int i;
791 :
792 4 : if (!nh || (nh->nh_type != NH_COMPOSITE) ||
793 4 : (!(nh->nh_flags & NH_FLAG_COMPOSITE_ECMP))) {
794 0 : return;
795 : }
796 :
797 4 : if (!req || !req->nhr_ecmp_config_hash) {
798 4 : nh->nh_ecmp_config_hash = ((VR_FLOW_KEY_ALL << 8) & 0xFF00);
799 4 : return;
800 : }
801 :
802 0 : flow_hash = 0;
803 0 : hash = req->nhr_ecmp_config_hash & NH_ECMP_CONFIG_HASH_MASK;
804 :
805 0 : for (i = 0; i < NH_ECMP_CONFIG_HASH_BITS; i++) {
806 0 : switch (hash & (1 << i)) {
807 0 : case NH_ECMP_CONFIG_HASH_PROTO:
808 0 : flow_hash |= VR_FLOW_KEY_PROTO;
809 0 : break;
810 0 : case NH_ECMP_CONFIG_HASH_SRC_IP:
811 0 : flow_hash |= VR_FLOW_KEY_SRC_IP;
812 0 : break;
813 0 : case NH_ECMP_CONFIG_HASH_SRC_PORT:
814 0 : flow_hash |= VR_FLOW_KEY_SRC_PORT;
815 0 : break;
816 0 : case NH_ECMP_CONFIG_HASH_DST_IP:
817 0 : flow_hash |= VR_FLOW_KEY_DST_IP;
818 0 : break;
819 0 : case NH_ECMP_CONFIG_HASH_DST_PORT:
820 0 : flow_hash |= VR_FLOW_KEY_DST_PORT;
821 0 : break;
822 0 : default:
823 0 : break;
824 : }
825 : }
826 :
827 : /* In the nh, store flow hash values in the second byte */
828 0 : nh->nh_ecmp_config_hash = hash | ((flow_hash << 8) & 0xFF00);
829 :
830 0 : return;
831 : }
832 :
833 :
834 : /*
835 : * Returns the ecmp nh index based on the reverse flows information. If
836 : * the reverse flow is created because of a packet on Fabric,
837 : * rflow_src_info contains tunnel's source IP, if created because of a
838 : * packet on VMI, it contains VMI's index. The ecmp nh is chosen in such
839 : * a way that packet is given to same reverse flow source
840 : */
841 : static int
842 1 : nh_composite_ecmp_select_by_rflow(struct vr_packet *pkt,
843 : struct vr_nexthop *nh, struct vr_forwarding_md *fmd,
844 : uint32_t rflow_src_info)
845 : {
846 : int index;
847 : uint32_t ip;
848 : struct vr_nexthop *cnh;
849 :
850 1 : ip = fmd->fmd_outer_src_ip;
851 1 : fmd->fmd_outer_src_ip = rflow_src_info;
852 3 : for (index = 0; index < nh->nh_component_cnt; index++) {
853 2 : cnh = nh->nh_component_nh[index].cnh;
854 2 : if (!cnh || !(cnh->nh_flags & NH_FLAG_VALID))
855 0 : continue;
856 :
857 : /*
858 : * Make use of tunnel's nh_validate_src as it validates the
859 : * tunnel source
860 : */
861 2 : if ((cnh->nh_type == NH_TUNNEL) && cnh->nh_validate_src) {
862 2 : if (NH_SOURCE_VALID == cnh->nh_validate_src(pkt, cnh, fmd, NULL))
863 0 : break;
864 : }
865 :
866 : /*
867 : * nh_validate_src cant be used as it compares VIF pointer for
868 : * encap. Validate the index explicitly
869 : */
870 2 : if (cnh->nh_type == NH_ENCAP) {
871 0 : if (cnh->nh_dev->vif_idx == rflow_src_info)
872 0 : break;
873 : }
874 : }
875 :
876 1 : fmd->fmd_outer_src_ip = ip;
877 1 : if (index == nh->nh_component_cnt)
878 1 : index = -1;
879 :
880 1 : return index;
881 : }
882 :
883 : static int
884 20 : nh_composite_ecmp_select_nh(struct vr_packet *pkt, struct vr_nexthop *nh,
885 : struct vr_forwarding_md *fmd)
886 : {
887 20 : bool hash_computed = false;
888 20 : int ret = -1, ecmp_index = -1;
889 : unsigned int hash, hash_ecmp, count, rflow_src_info;
890 :
891 20 : struct vr_flow flow, *flowp = &flow;
892 20 : struct vr_flow_entry *fe = NULL;
893 20 : struct vr_nexthop *cnh = NULL;
894 20 : struct vr_component_nh *cnhp = nh->nh_component_nh;
895 : struct vr_ip *ip;
896 : struct vr_ip6 *ip6;
897 : struct vr_packet *pkt_c;
898 :
899 20 : if (!nh || !fmd || (!nh->nh_component_cnt))
900 0 : return ret;
901 :
902 20 : count = nh->nh_component_cnt;
903 :
904 20 : if (fmd->fmd_flow_index >= 0) {
905 1 : fe = vr_flow_get_entry(nh->nh_router, fmd->fmd_flow_index);
906 1 : if (fe) {
907 1 : flowp = &fe->fe_key;
908 : /*
909 : * If the ecmp index is explicitly configured as -1, the
910 : * index need to be chosen as the one matchig with reverse
911 : * flow's source.
912 : */
913 1 : if (fmd->fmd_ecmp_nh_index == -1) {
914 1 : rflow_src_info = vr_flow_get_rflow_src_info(nh->nh_router, fe);
915 1 : if (rflow_src_info != (unsigned int)-1) {
916 1 : ecmp_index = nh_composite_ecmp_select_by_rflow(pkt,
917 : nh, fmd, rflow_src_info);
918 : }
919 : }
920 : }
921 : }
922 :
923 20 : if (!fe) {
924 : /*
925 : * If the flow entry does not exist, apply the configured
926 : * hash parameters to select candidate nexthop
927 : */
928 19 : hash = (nh->nh_ecmp_config_hash >> 8) & NH_ECMP_CONFIG_HASH_MASK;
929 19 : if (pkt->vp_type == VP_TYPE_IP) {
930 19 : ip = (struct vr_ip *)pkt_network_header(pkt);
931 19 : ret = vr_inet_get_flow_key(nh->nh_router, pkt, fmd,
932 : flowp, hash, VR_FRAG_FLAG_NONE);
933 19 : switch (ret) {
934 11 : case 0:
935 : /*
936 : * Handle head fragmented packets
937 : * - If this is a head fragment, clone it and enqueue it to the assembler
938 : * which would result in flushing of non-head fragments which
939 : * were queued earlier. The addition of head fragment to the fragment
940 : * hash table is taken care of in the get_flow_key().
941 : */
942 11 : if (vr_ip_fragment_head(ip) && vr_enqueue_to_assembler) {
943 2 : pkt_c = vr_pclone(pkt);
944 2 : if (pkt_c) {
945 2 : vr_enqueue_to_assembler(nh->nh_router, pkt_c, fmd);
946 : } else {
947 0 : pkt_drop_stats(pkt->vp_if, VP_DROP_CLONE_FAIL, pkt->vp_cpu);
948 : }
949 : }
950 11 : break;
951 :
952 8 : case -VP_DROP_NO_FRAG_ENTRY:
953 : /*
954 : * Handle non-head fragmented packets
955 : * - If the head fragment has not yet arrived, the fragment hash table
956 : * will not have any entry for it. In such cases, we cannot form
957 : * the flow key and get_flow_key() will fail. Such packets need to be
958 : * enqueued to the assembler. Once head fragment arrives, these
959 : * packets would be reinjected by the assembler.
960 : */
961 8 : if (!vr_ip_transport_header_valid(ip) && vr_enqueue_to_assembler) {
962 8 : vr_enqueue_to_assembler(nh->nh_router, pkt, fmd);
963 8 : return NH_ECMP_PACKET_HELD;
964 : }
965 0 : break;
966 0 : case -VP_DROP_ICMP_ERROR:
967 : case -VP_DROP_NO_MEMORY:
968 : default:
969 0 : return ret;
970 :
971 : }
972 0 : } else if (pkt->vp_type == VP_TYPE_IP6) {
973 0 : ip6 = (struct vr_ip6 *)pkt_network_header(pkt);
974 0 : ret = vr_inet6_get_flow_key(nh->nh_router, fmd->fmd_dvrf, pkt,
975 0 : fmd->fmd_vlan, flowp, hash, 0);
976 0 : switch (ret) {
977 0 : case 0:
978 0 : if (vr_ip6_fragment_head(ip6) && vr_enqueue_to_assembler) {
979 0 : pkt_c = vr_pclone(pkt);
980 0 : if (pkt_c) {
981 0 : vr_enqueue_to_assembler(nh->nh_router, pkt_c, fmd);
982 : } else {
983 0 : pkt_drop_stats(pkt->vp_if, VP_DROP_CLONE_FAIL, pkt->vp_cpu);
984 : }
985 : }
986 0 : break;
987 :
988 0 : case -VP_DROP_NO_FRAG_ENTRY:
989 0 : if (!vr_ip6_transport_header_valid(ip6) && vr_enqueue_to_assembler) {
990 0 : vr_enqueue_to_assembler(nh->nh_router, pkt, fmd);
991 0 : return NH_ECMP_PACKET_HELD;
992 : }
993 0 : break;
994 0 : case -VP_DROP_ICMP_ERROR:
995 : case -VP_DROP_NO_MEMORY:
996 : default:
997 0 : return ret;
998 :
999 : }
1000 : } else {
1001 : /*
1002 : * packet can be hashed on ethernet header and VRF to identify
1003 : * the component
1004 : */
1005 0 : hash_ecmp = vr_hash(pkt_data(pkt), VR_ETHER_HLEN, 0);
1006 0 : hash_ecmp = vr_hash_2words(hash_ecmp, fmd->fmd_dvrf, 0);
1007 0 : hash_computed = true;
1008 : }
1009 : }
1010 :
1011 :
1012 12 : if (ecmp_index == -1) {
1013 12 : if (!hash_computed)
1014 12 : hash_ecmp = vr_hash(flowp, flowp->flow_key_len, 0);
1015 12 : hash = hash_ecmp % count;
1016 12 : ecmp_index = cnhp[hash].cnh_ecmp_index;
1017 12 : cnh = cnhp[hash].cnh;
1018 12 : if (!cnh) {
1019 0 : if (nh->nh_component_ecmp_cnt) {
1020 0 : cnhp = nh->nh_component_ecmp;
1021 0 : hash_ecmp %= nh->nh_component_ecmp_cnt;
1022 0 : ecmp_index = cnhp[hash_ecmp].cnh_ecmp_index;
1023 0 : if (!(cnh = cnhp[hash_ecmp].cnh))
1024 0 : return -1;
1025 : }
1026 : }
1027 : }
1028 :
1029 12 : if (fe)
1030 1 : return vr_flow_update_ecmp_index(nh->nh_router, fe, ecmp_index, fmd);
1031 :
1032 11 : fmd->fmd_ecmp_nh_index = ecmp_index;
1033 :
1034 11 : return 0;
1035 : }
1036 :
1037 : static nh_processing_t
1038 24 : nh_composite_ecmp(struct vr_packet *pkt, struct vr_nexthop *nh,
1039 : struct vr_forwarding_md *fmd)
1040 : {
1041 24 : int ret = 0, drop_reason = VP_DROP_INVALID_NH;
1042 24 : struct vr_nexthop *member_nh = NULL;
1043 24 : struct vr_vrf_stats *stats = NULL;
1044 :
1045 24 : if (!fmd) {
1046 0 : drop_reason = VP_DROP_NO_FMD;
1047 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1048 0 : goto drop;
1049 : }
1050 :
1051 24 : if (vr_inet_vrf_stats) {
1052 24 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
1053 24 : if (stats)
1054 24 : stats->vrf_ecmp_composites++;
1055 : }
1056 :
1057 24 : if ((fmd->fmd_ecmp_nh_index >= 0) &&
1058 4 : (fmd->fmd_ecmp_nh_index < nh->nh_component_cnt)) {
1059 4 : member_nh = nh->nh_component_nh[fmd->fmd_ecmp_nh_index].cnh;
1060 : }
1061 :
1062 24 : if (!member_nh) {
1063 20 : ret = nh_composite_ecmp_select_nh(pkt, nh, fmd);
1064 20 : switch (ret) {
1065 12 : case 0:
1066 12 : break;
1067 8 : case NH_ECMP_PACKET_HELD:
1068 8 : return 0; /* packet was consumed */
1069 0 : case -VP_DROP_ICMP_ERROR:
1070 : case -VP_DROP_NO_MEMORY:
1071 : case -VP_DROP_NO_FRAG_ENTRY:
1072 0 : drop_reason = -ret;
1073 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1074 0 : goto drop;
1075 0 : default:
1076 0 : goto drop;
1077 : }
1078 :
1079 12 : member_nh = nh->nh_component_nh[fmd->fmd_ecmp_nh_index].cnh;
1080 12 : if (!member_nh)
1081 0 : goto drop;
1082 : }
1083 : /*
1084 : * this composite nh does not have vpn mpls label which should be
1085 : * derived from routelook only, so not overriding label retrieved from
1086 : * route lookup for label unicast composite nh case
1087 : */
1088 16 : if (!(nh->nh_flags & NH_FLAG_COMPOSITE_LU_ECMP)) {
1089 16 : vr_fmd_set_label(fmd, nh->nh_component_nh[fmd->fmd_ecmp_nh_index].cnh_label,
1090 : VR_LABEL_TYPE_UNKNOWN);
1091 : }
1092 16 : nh_output(pkt, member_nh, fmd);
1093 16 : return NH_PROCESSING_COMPLETE;
1094 :
1095 0 : drop:
1096 0 : vr_pfree(pkt, drop_reason);
1097 0 : return NH_PROCESSING_COMPLETE;
1098 : }
1099 :
1100 :
1101 : /*
1102 : * This function validate the source of the tunnel incase of L2
1103 : * multicast
1104 : */
1105 :
1106 : static int
1107 0 : nh_composite_mcast_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
1108 : struct vr_forwarding_md *fmd, void *ret_flags)
1109 : {
1110 : int i, j;
1111 : struct vr_nexthop *dir_nh, *fabric_nh;
1112 : unsigned int tun_dip;
1113 :
1114 : /*
1115 : * If multicast packet is received on fabric interface, we need to
1116 : * validate whether the source of this packet is in the distribution
1117 : * tree. If source is not in the list, packet needs to be dropped.
1118 : */
1119 :
1120 : /* Valid if source is VM */
1121 0 : if (pkt->vp_if->vif_type != VIF_TYPE_PHYSICAL)
1122 0 : return NH_SOURCE_VALID;
1123 :
1124 : /* If there is no source IP to compare treat it as invalid source */
1125 0 : if (!fmd->fmd_outer_src_ip)
1126 0 : return NH_SOURCE_INVALID;
1127 :
1128 0 : for(j = 0; j < nh->nh_component_cnt; j++) {
1129 0 : fabric_nh = nh->nh_component_nh[j].cnh;
1130 :
1131 0 : if (!fabric_nh || !(fabric_nh->nh_flags & NH_FLAG_VALID))
1132 0 : continue;
1133 :
1134 0 : if (fabric_nh->nh_type != NH_COMPOSITE ||
1135 0 : !(fabric_nh->nh_flags & (NH_FLAG_COMPOSITE_FABRIC |
1136 : NH_FLAG_COMPOSITE_EVPN | NH_FLAG_COMPOSITE_TOR)))
1137 0 : continue;
1138 :
1139 0 : for (i = 0; i < fabric_nh->nh_component_cnt; i++) {
1140 0 : dir_nh = fabric_nh->nh_component_nh[i].cnh;
1141 :
1142 : /* If direct nexthop is not valid, dont process it */
1143 0 : if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
1144 0 : continue;
1145 :
1146 0 : if (dir_nh->nh_type != NH_TUNNEL)
1147 0 : continue;
1148 :
1149 0 : tun_dip = 0;
1150 0 : if (dir_nh->nh_flags & NH_FLAG_TUNNEL_GRE)
1151 0 : tun_dip = dir_nh->nh_gre_tun_dip;
1152 0 : else if (dir_nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS)
1153 0 : tun_dip = dir_nh->nh_udp_tun_dip;
1154 0 : else if (dir_nh->nh_flags & NH_FLAG_TUNNEL_VXLAN)
1155 0 : tun_dip = dir_nh->nh_vxlan_tun_dip;
1156 :
1157 : /* If source is in districution tree, it is valid */
1158 0 : if (tun_dip && fmd->fmd_outer_src_ip &&
1159 0 : fmd->fmd_outer_src_ip == tun_dip) {
1160 :
1161 0 : if (ret_flags)
1162 0 : *((unsigned int *)ret_flags) = fabric_nh->nh_flags;
1163 :
1164 0 : return NH_SOURCE_VALID;
1165 : }
1166 : }
1167 : }
1168 :
1169 0 : if (!(nh->nh_flags & NH_FLAG_VALIDATE_MCAST_SRC)) {
1170 0 : *((unsigned int *)ret_flags) = NH_FLAG_VALIDATE_MCAST_SRC;
1171 0 : return NH_SOURCE_VALID;
1172 : }
1173 :
1174 0 : return NH_SOURCE_INVALID;
1175 : }
1176 :
1177 : static int
1178 0 : nh_handle_unknown_unicast(struct vr_packet *pkt, struct vr_eth *eth,
1179 : struct vr_forwarding_md *fmd, unsigned int pkt_src)
1180 : {
1181 0 : int handled = 1, pull_len;
1182 : struct vr_route_req rt;
1183 : struct vr_nexthop *nh;
1184 :
1185 : /*
1186 : * If packet is from VM or from TOR, we must have done a look up
1187 : * already in bridge before coming to this processing
1188 : */
1189 0 : if (!pkt_src || (pkt_src == PKT_SRC_TOR_REPL_TREE))
1190 0 : return !handled;
1191 :
1192 0 : rt.rtr_req.rtr_label_flags = 0;
1193 0 : rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX;
1194 0 : rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN;
1195 0 : rt.rtr_req.rtr_mac = eth->eth_dmac;
1196 0 : rt.rtr_req.rtr_vrf_id = fmd->fmd_dvrf;
1197 :
1198 0 : nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt);
1199 0 : if (!nh || nh->nh_type != NH_ENCAP)
1200 0 : return !handled;
1201 :
1202 : /* Get the packet to eth header */
1203 0 : pull_len = (uintptr_t)eth - (uintptr_t)pkt_data(pkt);
1204 0 : if (pull_len)
1205 0 : pkt_pull(pkt, pull_len);
1206 :
1207 0 : nh_output(pkt, nh, fmd);
1208 :
1209 0 : return handled;
1210 : }
1211 :
1212 : static int
1213 0 : nh_handle_mcast_control_pkt(struct vr_packet *pkt, struct vr_eth *eth,
1214 : struct vr_forwarding_md *fmd, unsigned int pkt_src, bool *flood_to_vms)
1215 : {
1216 0 : int handled = 1;
1217 : unsigned char eth_dmac[VR_ETHER_ALEN];
1218 0 : bool flood = false;
1219 0 : unsigned short trap, rt_flags, drop_reason, pull_len = 0;
1220 0 : l4_pkt_type_t l4_type = L4_TYPE_UNKNOWN;
1221 : struct vr_arp *sarp;
1222 : struct vr_nexthop *src_nh;
1223 : struct vr_ip6 *ip6;
1224 :
1225 0 : struct vr_packet *pkt_c = NULL;
1226 :
1227 : /*
1228 : * The vlan tagged packets are meant to be handled only by VM's
1229 : */
1230 0 : if (fmd->fmd_vlan != VLAN_ID_INVALID)
1231 0 : return !handled;
1232 :
1233 0 : pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
1234 0 : if (!pkt_pull(pkt, pull_len)) {
1235 0 : drop_reason = VP_DROP_PULL;
1236 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1237 0 : goto drop;
1238 : }
1239 :
1240 0 : rt_flags = vr_bridge_route_flags(fmd->fmd_dvrf, eth->eth_smac);
1241 :
1242 0 : if (pkt->vp_type == VP_TYPE_ARP) {
1243 :
1244 0 : if ((pkt_src == PKT_SRC_INGRESS_REPL_TREE) &&
1245 0 : (rt_flags & VR_BE_EVPN_CONTROL_PROCESSING_FLAG)) {
1246 0 : fmd->fmd_src = TOR_EVPN_SOURCE;
1247 : }
1248 :
1249 0 : VR_MAC_COPY(eth_dmac, eth->eth_dmac);
1250 0 : handled = vr_arp_input(pkt, fmd, eth_dmac);
1251 0 : if (handled)
1252 0 : return handled;
1253 :
1254 : /*
1255 : * If not handled, packet needs to be flooded. If the ARP is
1256 : * from MX, VM's should not see this ARP as VM's always need to
1257 : * see Agent as gateway
1258 : */
1259 :
1260 0 : if (pkt_src) {
1261 0 : sarp = (struct vr_arp *)pkt_data(pkt);
1262 0 : src_nh = vr_inet_ip_lookup(fmd->fmd_dvrf, sarp->arp_spa);
1263 0 : if (vr_gateway_nexthop(src_nh)) {
1264 0 : *flood_to_vms = false;
1265 : }
1266 : }
1267 :
1268 0 : goto unhandled;
1269 : }
1270 :
1271 0 : if ((pkt->vp_type != VP_TYPE_IP) && (pkt->vp_type != VP_TYPE_IP6))
1272 0 : goto unhandled;
1273 :
1274 : /*
1275 : * V6 Ndisc, router solictation packets are ICMP packets. So we need
1276 : * to parse to identify the type, unlike V4 ARP
1277 : */
1278 0 : if (pkt->vp_type == VP_TYPE_IP6) {
1279 0 : l4_type = vr_ip6_well_known_packet(pkt);
1280 0 : } else if (pkt_src == (PKT_SRC_TOR_REPL_TREE) ||
1281 : (pkt_src == PKT_SRC_INGRESS_REPL_TREE)) {
1282 0 : l4_type = vr_ip_well_known_packet(pkt);
1283 : }
1284 :
1285 : /*
1286 : * Special control packets need to be handled only if VM or BMS
1287 : * behind OvsDB Tor or BMS behind Evpn Tor(which will have
1288 : * VR_BE_EVPN_CONTROL_PROCESSING_FLAG)
1289 : */
1290 0 : if ((!pkt_src) || (pkt_src == PKT_SRC_TOR_REPL_TREE) ||
1291 0 : ((pkt_src == PKT_SRC_INGRESS_REPL_TREE) &&
1292 0 : (rt_flags & VR_BE_EVPN_CONTROL_PROCESSING_FLAG))) {
1293 :
1294 : /*
1295 : * If packet is identified as known packet, we always trap
1296 : * it to agent with the exception of DHCP. DHCP can be flooded
1297 : * depending on the configuration on VMI or L2 route flags
1298 : */
1299 0 : if (l4_type != L4_TYPE_UNKNOWN) {
1300 :
1301 0 : trap = true;
1302 :
1303 0 : if (l4_type == L4_TYPE_DHCP_REQUEST) {
1304 0 : if (rt_flags & VR_BE_FLOOD_DHCP_FLAG)
1305 0 : trap = false;
1306 0 : } else if (l4_type == L4_TYPE_NEIGHBOUR_SOLICITATION) {
1307 0 : trap = false;
1308 0 : } else if (l4_type == L4_TYPE_NEIGHBOUR_ADVERTISEMENT) {
1309 0 : flood = true;
1310 : }
1311 :
1312 0 : if (trap && flood) {
1313 0 : pkt_c = nh_mcast_clone(pkt, AGENT_PKT_HEAD_SPACE);
1314 0 : if (!pkt_c) {
1315 0 : trap = false;
1316 : }
1317 : }
1318 :
1319 0 : if (trap) {
1320 0 : if (flood) {
1321 0 : vr_trap(pkt_c, fmd->fmd_dvrf,
1322 : AGENT_TRAP_L3_PROTOCOLS, NULL);
1323 0 : goto unhandled;
1324 : } else {
1325 0 : vr_trap(pkt, fmd->fmd_dvrf,
1326 : AGENT_TRAP_L3_PROTOCOLS, NULL);
1327 0 : return handled;
1328 : }
1329 : }
1330 : }
1331 : }
1332 :
1333 0 : if (l4_type == L4_TYPE_NEIGHBOUR_SOLICITATION) {
1334 0 : VR_MAC_COPY(eth_dmac, eth->eth_dmac);
1335 0 : handled = vr_neighbor_input(pkt, fmd, eth_dmac);
1336 0 : if (handled)
1337 0 : return handled;
1338 :
1339 0 : if (pkt_src) {
1340 0 : ip6 = (struct vr_ip6 *)pkt_data(pkt);
1341 0 : src_nh = vr_inet6_ip_lookup(fmd->fmd_dvrf, ip6->ip6_src);
1342 0 : if (vr_gateway_nexthop(src_nh))
1343 0 : *flood_to_vms = false;
1344 : }
1345 : }
1346 :
1347 0 : unhandled:
1348 0 : if (pull_len)
1349 0 : pkt_push(pkt, pull_len);
1350 0 : return 0;
1351 :
1352 0 : drop:
1353 0 : vr_pfree(pkt, drop_reason);
1354 0 : return 1;
1355 : }
1356 :
1357 : static nh_processing_t
1358 0 : nh_composite_mcast(struct vr_packet *pkt, struct vr_nexthop *nh,
1359 : struct vr_forwarding_md *fmd)
1360 : {
1361 :
1362 : int i, clone_size;
1363 0 : bool flood_to_vms = true, l2_control_data = false;
1364 0 : unsigned short drop_reason, label, pkt_vrf, pull_len = 0,
1365 0 : pbb_pull_len = 0;
1366 : unsigned int tun_src, pkt_src, hashval, port_range, handled;
1367 : mac_learn_t ml_res;
1368 0 : struct vr_eth *eth = NULL;
1369 : struct vr_nexthop *dir_nh;
1370 : struct vr_packet *new_pkt;
1371 0 : struct vr_vrf_stats *stats = NULL;
1372 : // Context for the flag:
1373 : // For 5.1, mcast source is outside contrail and only <*,G> is supported.
1374 : // Until such a time when source can be inside contrail, multicast data
1375 : // packets sourced from inside contrail has to be dropped.
1376 : // Also, packets originating outside of contrail has pkt->vp_data pointing
1377 : // to inner ethernet header (in case of VxLan tunneled packet).
1378 0 : bool pull_header = true;
1379 :
1380 0 : if (!fmd) {
1381 0 : drop_reason = VP_DROP_NO_FMD;
1382 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1383 0 : goto drop;
1384 : }
1385 :
1386 0 : if (vr_inet_vrf_stats) {
1387 0 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
1388 0 : if (stats)
1389 0 : stats->vrf_l2_mcast_composites++;
1390 : }
1391 :
1392 0 : pkt_vrf = fmd->fmd_dvrf;
1393 0 : drop_reason = VP_DROP_CLONED_ORIGINAL;
1394 :
1395 : /*
1396 : * nh_validate_src identifies the format of the packet and source of
1397 : * the packet too. Without this callback being defined we will not
1398 : * be able to replicate the packet
1399 : */
1400 0 : if (!nh->nh_validate_src) {
1401 0 : drop_reason = VP_DROP_MISC;
1402 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1403 0 : goto drop;
1404 : }
1405 :
1406 0 : tun_src = pkt_src = 0;
1407 0 : if (nh->nh_validate_src(pkt, nh, fmd, &tun_src) == NH_SOURCE_INVALID) {
1408 0 : drop_reason = VP_DROP_INVALID_MCAST_SOURCE;
1409 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1410 0 : goto drop;
1411 : }
1412 :
1413 0 : if (tun_src & NH_FLAG_COMPOSITE_EVPN)
1414 0 : pkt_src = PKT_SRC_INGRESS_REPL_TREE;
1415 :
1416 0 : if (tun_src & NH_FLAG_COMPOSITE_FABRIC) {
1417 0 : pkt_src = PKT_SRC_EDGE_REPL_TREE;
1418 0 : if (nh->nh_family == AF_BRIDGE)
1419 0 : pull_len = VR_VXLAN_HDR_LEN;
1420 : }
1421 :
1422 0 : if (tun_src & NH_FLAG_VALIDATE_MCAST_SRC) {
1423 : // Since source check is relaxed, tunnel source is hard-coded to
1424 : // fabric.
1425 0 : tun_src = NH_FLAG_COMPOSITE_FABRIC;
1426 0 : pkt_src = PKT_SRC_EDGE_REPL_TREE;
1427 : // In this case ethernet header pointer need not be adjusted.
1428 0 : pull_header = false;
1429 : }
1430 :
1431 0 : if (tun_src & NH_FLAG_COMPOSITE_TOR) {
1432 0 : pkt_src = PKT_SRC_TOR_REPL_TREE;
1433 0 : fmd->fmd_src = TOR_SOURCE;
1434 : }
1435 :
1436 0 : if (nh->nh_family == AF_BRIDGE) {
1437 0 : eth = (struct vr_eth *)pkt_data_at_offset(pkt,
1438 0 : pkt->vp_data + pull_len);
1439 :
1440 0 : if (ntohs(eth->eth_proto) == VR_ETH_PROTO_PBB) {
1441 0 : pbb_pull_len = __vr_pbb_decode(eth, pkt_head_len(pkt) - pull_len, fmd);
1442 0 : if (pbb_pull_len <= 0) {
1443 0 : drop_reason = VP_DROP_INVALID_PACKET;
1444 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1445 0 : goto drop;
1446 : }
1447 :
1448 0 : if (vr_pkt_type(pkt, pbb_pull_len + pull_len, fmd) < 0) {
1449 0 : drop_reason = VP_DROP_INVALID_PACKET;
1450 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1451 0 : goto drop;
1452 : }
1453 :
1454 0 : eth = (struct vr_eth *)(((char *)eth) + pbb_pull_len);
1455 0 : if (nh->nh_flags & NH_FLAG_MAC_LEARN) {
1456 0 : ml_res = vr_bridge_learn(nh->nh_router, pkt, eth, fmd);
1457 0 : if (ml_res == MAC_TRAPPED)
1458 0 : return NH_PROCESSING_COMPLETE;
1459 : }
1460 : }
1461 :
1462 0 : handled = nh_handle_mcast_control_pkt(pkt, eth, fmd,
1463 : pkt_src, &flood_to_vms);
1464 0 : if (handled)
1465 0 : return NH_PROCESSING_COMPLETE;
1466 :
1467 0 : if (flood_to_vms && !IS_MAC_BMCAST(eth->eth_dmac)) {
1468 0 : handled = nh_handle_unknown_unicast(pkt, eth, fmd, pkt_src);
1469 0 : if (handled)
1470 0 : return NH_PROCESSING_COMPLETE;
1471 : }
1472 :
1473 :
1474 : /*
1475 : * The packet can come to this nexthp either from Fabric or from VM.
1476 : * Incase of Fabric, the packet would contain the Vxlan header and
1477 : * control information. From VM, it contains neither of them
1478 : */
1479 :
1480 0 : if (!fmd->fmd_udp_src_port) {
1481 0 : if (hashrnd_inited == 0) {
1482 0 : get_random_bytes(&vr_hashrnd, sizeof(vr_hashrnd));
1483 0 : hashrnd_inited = 1;
1484 : }
1485 0 : hashval = vr_hash(eth, sizeof(struct vr_eth), vr_hashrnd);
1486 : /* Include the VRF to calculate the hash */
1487 0 : hashval = vr_hash_2words(hashval, fmd->fmd_dvrf, vr_hashrnd);
1488 :
1489 : /*
1490 : * Convert the hash value to a value in the port range that we want
1491 : * for dynamic UDP ports
1492 : */
1493 0 : port_range = VR_MUDP_PORT_RANGE_END - VR_MUDP_PORT_RANGE_START;
1494 0 : fmd->fmd_udp_src_port = (uint16_t) (((uint64_t) hashval * port_range) >> 32);
1495 :
1496 0 : if (fmd->fmd_udp_src_port > port_range) {
1497 : /*
1498 : * Shouldn't happen...
1499 : */
1500 0 : fmd->fmd_udp_src_port = 0;
1501 : }
1502 :
1503 0 : fmd->fmd_udp_src_port += VR_MUDP_PORT_RANGE_START;
1504 : }
1505 :
1506 0 : if (vr_fmd_l2_control_data_is_enabled(fmd))
1507 0 : l2_control_data = true;
1508 : }
1509 :
1510 0 : if (!nh->nh_component_cnt) {
1511 0 : drop_reason = VP_DROP_DISCARD;
1512 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1513 0 : goto drop;
1514 : }
1515 :
1516 0 : label = fmd->fmd_label;
1517 :
1518 0 : for (i = 0; i < nh->nh_component_cnt; i++) {
1519 0 : clone_size = 0;
1520 0 : dir_nh = nh->nh_component_nh[i].cnh;
1521 :
1522 : /* We need to copy back the original label from Bridge lookaup
1523 : * as previous iteration would have manipulated that
1524 : */
1525 0 : vr_fmd_set_label(fmd, label, VR_LABEL_TYPE_UNKNOWN);
1526 0 : fmd->fmd_dvrf = pkt_vrf;
1527 0 : vr_fmd_update_l2_control_data(fmd, false);
1528 :
1529 : /* If direct nexthop is not valid, dont process it */
1530 0 : if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID) ||
1531 0 : (dir_nh->nh_type != NH_COMPOSITE))
1532 0 : continue;
1533 :
1534 0 : if (dir_nh->nh_flags & NH_FLAG_COMPOSITE_ENCAP) {
1535 0 : if (!flood_to_vms)
1536 0 : continue;
1537 :
1538 0 : if (!(new_pkt = nh_mcast_clone(pkt, 0))) {
1539 0 : drop_reason = VP_DROP_MCAST_CLONE_FAIL;
1540 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1541 0 : break;
1542 : }
1543 :
1544 0 : pull_len = pbb_pull_len;
1545 0 : if (nh->nh_family == AF_BRIDGE &&
1546 : (pkt_src == PKT_SRC_EDGE_REPL_TREE)) {
1547 0 : if (pull_header) {
1548 0 : pull_len += VR_VXLAN_HDR_LEN;
1549 : }
1550 : }
1551 :
1552 0 : if (pull_len && !pkt_pull(new_pkt, pull_len)) {
1553 0 : vr_pfree(new_pkt, VP_DROP_PULL);
1554 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1555 0 : break;
1556 : }
1557 0 : } else if (dir_nh->nh_flags & NH_FLAG_COMPOSITE_FABRIC) {
1558 0 : if (pkt_src == PKT_SRC_INGRESS_REPL_TREE)
1559 0 : continue;
1560 :
1561 0 : if (pkt_src != PKT_SRC_EDGE_REPL_TREE) {
1562 0 : if (nh->nh_family == AF_BRIDGE) {
1563 0 : clone_size += VR_L2_MCAST_PKT_HEAD_SPACE;
1564 0 : if (dir_nh->nh_flags & NH_FLAG_TUNNEL_PBB)
1565 0 : clone_size += VR_ETHER_HLEN + sizeof(struct vr_pbb_itag);
1566 : } else {
1567 0 : clone_size += VR_L3_MCAST_PKT_HEAD_SPACE;
1568 : }
1569 : }
1570 :
1571 : /* Create head space for L2 Mcast header */
1572 0 : if (!(new_pkt = nh_mcast_clone(pkt, clone_size))) {
1573 0 : drop_reason = VP_DROP_MCAST_CLONE_FAIL;
1574 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1575 0 : break;
1576 : }
1577 0 : if (!pull_header) {
1578 : // Recover header space to write tunnel header when sending to
1579 : // other computes. Assumption is that multicast data packet was
1580 : // received from outside contrail using vxlan header.
1581 0 : pkt_push(new_pkt, VR_VXLAN_HDR_LEN);
1582 : }
1583 0 : fmd->fmd_dvrf = dir_nh->nh_vrf;
1584 :
1585 0 : } else if (dir_nh->nh_flags & NH_FLAG_COMPOSITE_EVPN) {
1586 :
1587 : /* We replicate only if received from VM and Ovs TOR*/
1588 0 : if ((!pkt_src)|| (pkt_src == PKT_SRC_TOR_REPL_TREE)) {
1589 :
1590 : /* Create head space for non Vxlan header */
1591 0 : clone_size = VR_L3_MCAST_PKT_HEAD_SPACE;
1592 0 : if (nh->nh_flags & NH_FLAG_L2_CONTROL_DATA)
1593 0 : clone_size += VR_L2_CTRL_DATA_LEN;
1594 0 : if (dir_nh->nh_flags & NH_FLAG_TUNNEL_PBB)
1595 0 : clone_size += VR_ETHER_HLEN + sizeof(struct vr_pbb_itag);
1596 :
1597 0 : if (!(new_pkt = nh_mcast_clone(pkt, clone_size))) {
1598 0 : drop_reason = VP_DROP_MCAST_CLONE_FAIL;
1599 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1600 0 : break;
1601 : }
1602 0 : fmd->fmd_dvrf = dir_nh->nh_vrf;
1603 : } else {
1604 0 : continue;
1605 : }
1606 :
1607 0 : if (l2_control_data)
1608 0 : vr_fmd_update_l2_control_data(fmd, true);
1609 :
1610 0 : } else if (dir_nh->nh_flags & NH_FLAG_COMPOSITE_TOR) {
1611 :
1612 : /* Create head space for Vxlan header */
1613 0 : clone_size = VR_L2_MCAST_PKT_HEAD_SPACE - VR_L2_CTRL_DATA_LEN;
1614 0 : if (!(new_pkt = nh_mcast_clone(pkt, clone_size))) {
1615 0 : drop_reason = VP_DROP_MCAST_CLONE_FAIL;
1616 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1617 0 : break;
1618 : }
1619 :
1620 0 : if (pkt_src == PKT_SRC_EDGE_REPL_TREE) {
1621 :
1622 0 : pull_len = VR_VXLAN_HDR_LEN + pbb_pull_len;
1623 0 : if (!pkt_pull(new_pkt, pull_len)) {
1624 0 : vr_pfree(new_pkt, VP_DROP_PULL);
1625 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1626 0 : break;
1627 : }
1628 : }
1629 0 : fmd->fmd_dvrf = dir_nh->nh_vrf;
1630 :
1631 : } else {
1632 0 : continue;
1633 : }
1634 :
1635 0 : nh_output(new_pkt, dir_nh, fmd);
1636 : }
1637 :
1638 : /* Original packet needs to be unconditionally dropped */
1639 0 : drop:
1640 0 : vr_pfree(pkt, drop_reason);
1641 0 : return NH_PROCESSING_COMPLETE;
1642 : }
1643 :
1644 :
1645 : static nh_processing_t
1646 0 : nh_composite_encap(struct vr_packet *pkt, struct vr_nexthop *nh,
1647 : struct vr_forwarding_md *fmd)
1648 : {
1649 : int i, j;
1650 0 : struct vr_vrf_stats *stats = NULL;
1651 : struct vr_nexthop *dir_nh;
1652 : unsigned short drop_reason;
1653 : struct vr_packet *new_pkt;
1654 :
1655 0 : if (!fmd) {
1656 0 : drop_reason = VP_DROP_NO_FMD;
1657 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1658 0 : goto drop;
1659 : }
1660 :
1661 0 : drop_reason = VP_DROP_CLONED_ORIGINAL;
1662 0 : if (vr_inet_vrf_stats) {
1663 0 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
1664 0 : if (stats)
1665 0 : stats->vrf_encap_composites++;
1666 : }
1667 :
1668 0 : if (!nh->nh_component_cnt) {
1669 0 : drop_reason = VP_DROP_DISCARD;
1670 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1671 0 : goto drop;
1672 : }
1673 :
1674 0 : for (i = 0; i < nh->nh_component_cnt; i++) {
1675 0 : dir_nh = nh->nh_component_nh[i].cnh;
1676 :
1677 : /* If direct nexthop is not valid, dont process it */
1678 0 : if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
1679 0 : continue;
1680 :
1681 : /* Dont give back the packet to same VM */
1682 0 : if (dir_nh->nh_dev == pkt->vp_if)
1683 0 : continue;
1684 :
1685 : /* There would be enought head space to clone it with zero size */
1686 0 : if (!(new_pkt = nh_mcast_clone(pkt, 0))) {
1687 0 : drop_reason = VP_DROP_MCAST_CLONE_FAIL;
1688 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1689 0 : break;
1690 : }
1691 :
1692 0 : for (j = 0; j < VR_MAX_PHY_INF; j++) {
1693 0 : if (dir_nh->nh_dev_arr[j] != NULL) {
1694 0 : fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
1695 0 : break;
1696 : }
1697 : }
1698 0 : nh_output(new_pkt, dir_nh, fmd);
1699 : }
1700 :
1701 : /* Original packet needs to be unconditionally dropped */
1702 0 : drop:
1703 0 : vr_pfree(pkt, drop_reason);
1704 0 : return NH_PROCESSING_COMPLETE;
1705 : }
1706 :
1707 : static nh_processing_t
1708 0 : nh_composite_tor(struct vr_packet *pkt, struct vr_nexthop *nh,
1709 : struct vr_forwarding_md *fmd)
1710 : {
1711 : int i, j;
1712 0 : struct vr_vrf_stats *stats = NULL;
1713 : struct vr_nexthop *dir_nh;
1714 : unsigned short drop_reason;
1715 : struct vr_packet *new_pkt;
1716 :
1717 0 : if (!fmd) {
1718 0 : drop_reason = VP_DROP_NO_FMD;
1719 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1720 0 : goto drop;
1721 : }
1722 :
1723 0 : drop_reason = VP_DROP_CLONED_ORIGINAL;
1724 0 : if (vr_inet_vrf_stats) {
1725 0 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
1726 0 : if (stats)
1727 0 : stats->vrf_evpn_composites++;
1728 : }
1729 :
1730 0 : if (!nh->nh_component_cnt) {
1731 0 : drop_reason = VP_DROP_DISCARD;
1732 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1733 0 : goto drop;
1734 : }
1735 :
1736 0 : for (i = 0; i < nh->nh_component_cnt; i++) {
1737 0 : dir_nh = nh->nh_component_nh[i].cnh;
1738 :
1739 : /* If direct nexthop is not valid, dont process it */
1740 0 : if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
1741 0 : continue;
1742 :
1743 0 : if (dir_nh->nh_type != NH_TUNNEL)
1744 0 : continue;
1745 :
1746 : /* Dont forward to same source */
1747 0 : if (fmd->fmd_outer_src_ip && fmd->fmd_outer_src_ip ==
1748 0 : dir_nh->nh_udp_tun_dip)
1749 0 : continue;
1750 :
1751 : /*
1752 : * Enough head spaces are created in the previous nexthop
1753 : * handling. Just cow the packet with zero size to get different
1754 : * buffer space
1755 : */
1756 0 : new_pkt = nh_mcast_clone(pkt, 0);
1757 0 : if (!new_pkt) {
1758 0 : drop_reason = VP_DROP_MCAST_CLONE_FAIL;
1759 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1760 0 : break;
1761 : }
1762 :
1763 0 : vr_fmd_set_label(fmd, nh->nh_component_nh[i].cnh_label,
1764 : VR_LABEL_TYPE_UNKNOWN);
1765 0 : for (j = 0; j < VR_MAX_PHY_INF; j++) {
1766 0 : if (dir_nh->nh_dev_arr[j] != NULL) {
1767 0 : fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
1768 0 : break;
1769 : }
1770 : }
1771 0 : nh_output(new_pkt, dir_nh, fmd);
1772 : }
1773 :
1774 : /* Original packet needs to be unconditionally dropped */
1775 0 : drop:
1776 0 : vr_pfree(pkt, drop_reason);
1777 0 : return NH_PROCESSING_COMPLETE;
1778 : }
1779 :
1780 : static nh_processing_t
1781 0 : nh_composite_evpn(struct vr_packet *pkt, struct vr_nexthop *nh,
1782 : struct vr_forwarding_md *fmd)
1783 : {
1784 : int i, j;
1785 0 : bool l2_control_data = false;
1786 0 : struct vr_vrf_stats *stats = NULL;
1787 : struct vr_nexthop *dir_nh;
1788 : unsigned short drop_reason;
1789 : struct vr_packet *new_pkt;
1790 : uint8_t eth_mac[VR_ETHER_ALEN];
1791 :
1792 0 : if (!fmd) {
1793 0 : drop_reason = VP_DROP_NO_FMD;
1794 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1795 0 : goto drop;
1796 : }
1797 :
1798 0 : drop_reason = VP_DROP_CLONED_ORIGINAL;
1799 0 : if (vr_inet_vrf_stats) {
1800 0 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
1801 0 : if (stats)
1802 0 : stats->vrf_evpn_composites++;
1803 : }
1804 :
1805 0 : if (!nh->nh_component_cnt) {
1806 0 : drop_reason = VP_DROP_DISCARD;
1807 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1808 0 : goto drop;
1809 : }
1810 :
1811 0 : if (nh->nh_flags & NH_FLAG_TUNNEL_PBB)
1812 0 : vr_mcast_mac_from_isid(pkt->vp_if->vif_isid, eth_mac);
1813 :
1814 0 : if (vr_fmd_l2_control_data_is_enabled(fmd)) {
1815 0 : l2_control_data = true;
1816 0 : vr_fmd_update_l2_control_data(fmd, false);
1817 : }
1818 :
1819 0 : for (i = 0; i < nh->nh_component_cnt; i++) {
1820 0 : dir_nh = nh->nh_component_nh[i].cnh;
1821 :
1822 : /* If direct nexthop is not valid, dont process it */
1823 0 : if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
1824 0 : continue;
1825 :
1826 0 : if (dir_nh->nh_type != NH_TUNNEL)
1827 0 : continue;
1828 :
1829 : /*
1830 : * Enough head spaces are created in the previous nexthop
1831 : * handling. Just cow the packet with zero size to get different
1832 : * buffer space
1833 : */
1834 0 : new_pkt = nh_mcast_clone(pkt, 0);
1835 0 : if (!new_pkt) {
1836 0 : drop_reason = VP_DROP_MCAST_CLONE_FAIL;
1837 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1838 0 : break;
1839 : }
1840 :
1841 0 : if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
1842 0 : if (!nh_pbb_tunnel_helper(nh->nh_router, &new_pkt, fmd,
1843 0 : eth_mac, pkt->vp_if->vif_pbb_mac, pkt->vp_if->vif_isid)) {
1844 0 : PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
1845 0 : vr_pfree(new_pkt, VP_DROP_PUSH);
1846 0 : continue;
1847 : }
1848 : }
1849 :
1850 0 : if (l2_control_data && !vr_l2_control_data_add(&new_pkt)) {
1851 0 : drop_reason = VP_DROP_PULL;
1852 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1853 0 : break;
1854 : }
1855 :
1856 0 : vr_fmd_set_label(fmd, nh->nh_component_nh[i].cnh_label,
1857 : VR_LABEL_TYPE_UNKNOWN);
1858 0 : for (j = 0; j < VR_MAX_PHY_INF; j++) {
1859 0 : if (dir_nh->nh_dev_arr[j] != NULL) {
1860 0 : fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
1861 0 : break;
1862 : }
1863 : }
1864 0 : nh_output(new_pkt, dir_nh, fmd);
1865 : }
1866 :
1867 : /* Original packet needs to be unconditionally dropped */
1868 0 : drop:
1869 0 : vr_pfree(pkt, drop_reason);
1870 0 : return NH_PROCESSING_COMPLETE;
1871 : }
1872 :
1873 : static nh_processing_t
1874 2 : nh_composite_fabric(struct vr_packet *pkt, struct vr_nexthop *nh,
1875 : struct vr_forwarding_md *fmd)
1876 : {
1877 2 : int i, j, flag = 0;
1878 : int32_t label;
1879 : unsigned int dip, sip;
1880 : int8_t eth_mac[VR_ETHER_ALEN];
1881 2 : struct vr_vrf_stats *stats = NULL;
1882 : struct vr_nexthop *dir_nh;
1883 : unsigned short drop_reason, pkt_vrf;
1884 : struct vr_packet *new_pkt;
1885 :
1886 2 : if (!fmd) {
1887 0 : drop_reason = VP_DROP_NO_FMD;
1888 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1889 0 : goto drop;
1890 : }
1891 :
1892 2 : drop_reason = VP_DROP_CLONED_ORIGINAL;
1893 2 : if (vr_inet_vrf_stats) {
1894 2 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
1895 2 : if (stats)
1896 2 : stats->vrf_fabric_composites++;
1897 : }
1898 :
1899 2 : if (!nh->nh_component_cnt) {
1900 0 : drop_reason = VP_DROP_DISCARD;
1901 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1902 0 : goto drop;
1903 : }
1904 :
1905 : /*
1906 : * Packet can be L2 or L3 with or without control information. It is
1907 : * always ensured before coming to this nexthop that packet headers
1908 : * along with control inforation is in first buffer. So it can be
1909 : * safely cow'd for the required length
1910 : */
1911 :
1912 2 : label = fmd->fmd_label;
1913 2 : pkt_vrf = fmd->fmd_dvrf;
1914 2 : if (nh->nh_flags & NH_FLAG_TUNNEL_PBB)
1915 0 : vr_mcast_mac_from_isid(pkt->vp_if->vif_isid, eth_mac);
1916 :
1917 4 : for (i = 0; i < nh->nh_component_cnt; i++) {
1918 2 : dir_nh = nh->nh_component_nh[i].cnh;
1919 2 : flag = 0;
1920 2 : fmd->fmd_dvrf = pkt_vrf;
1921 :
1922 : /* If direct nexthop is not valid, dont process it */
1923 2 : if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
1924 0 : continue;
1925 :
1926 2 : if (dir_nh->nh_type != NH_TUNNEL)
1927 0 : continue;
1928 :
1929 : /*
1930 : * Take the right tunnel source. The dst is also our own
1931 : * address
1932 : */
1933 2 : sip = dip = 0;
1934 2 : if (dir_nh->nh_flags & NH_FLAG_TUNNEL_GRE) {
1935 0 : sip = dir_nh->nh_gre_tun_sip;
1936 0 : dip = dir_nh->nh_gre_tun_dip;
1937 2 : } else if (dir_nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS) {
1938 2 : sip = dir_nh->nh_udp_tun_sip;
1939 2 : dip = dir_nh->nh_udp_tun_dip;
1940 : } else {
1941 0 : drop_reason = VP_DROP_INVALID_NH;
1942 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1943 0 : break;
1944 : }
1945 :
1946 : /* Dont forward to same source */
1947 2 : if (fmd->fmd_outer_src_ip && fmd->fmd_outer_src_ip == dip)
1948 0 : continue;
1949 :
1950 : /* Dont flood back on ingress physical interface on the fabric. */
1951 2 : if (vif_is_vlan(pkt->vp_if)) {
1952 0 : for (j = 0; j < VR_MAX_PHY_INF; j++) {
1953 0 : if (dir_nh->nh_dev_arr[j] != NULL) {
1954 0 : if (vif_is_vlan(dir_nh->nh_dev_arr[j]) &&
1955 0 : pkt->vp_if->vif_parent == dir_nh->nh_dev_arr[j]->vif_parent) {
1956 0 : flag = 1;
1957 0 : break;
1958 0 : } else if (pkt->vp_if->vif_parent == dir_nh->nh_dev_arr[j]) {
1959 0 : flag = 1;
1960 0 : break;
1961 : }
1962 : }
1963 : }
1964 0 : if (flag == 1)
1965 0 : continue;
1966 : }
1967 :
1968 : /*
1969 : * Enough head spaces are created in the previous nexthop
1970 : * handling. Just cow the packet with zero size to get different
1971 : * buffer space
1972 : */
1973 2 : new_pkt = nh_mcast_clone(pkt, 0);
1974 2 : if (!new_pkt) {
1975 0 : drop_reason = VP_DROP_MCAST_CLONE_FAIL;
1976 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
1977 0 : break;
1978 : }
1979 :
1980 : /* If from VM or Tor add vxlan header */
1981 2 : if (vif_is_virtual(new_pkt->vp_if) ||
1982 0 : (fmd->fmd_src == TOR_SOURCE)) {
1983 : /*
1984 : * The L2 multicast bridge entry will have VNID as label. If fmd
1985 : * does not valid label/vnid, skip the processing
1986 : */
1987 2 : if (label < 0) {
1988 0 : PKT_LOG(VP_DROP_INVALID_LABEL, pkt, 0, VR_NEXTHOP_C, __LINE__);
1989 0 : vr_pfree(new_pkt, VP_DROP_INVALID_LABEL);
1990 0 : break;
1991 : }
1992 :
1993 2 : if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
1994 0 : if (!nh_pbb_tunnel_helper(nh->nh_router, &new_pkt, fmd, eth_mac,
1995 0 : pkt->vp_if->vif_pbb_mac, pkt->vp_if->vif_isid)) {
1996 0 : PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
1997 0 : vr_pfree(new_pkt, VP_DROP_PUSH);
1998 0 : continue;
1999 : }
2000 : }
2001 :
2002 2 : if (nh->nh_family == AF_BRIDGE) {
2003 : /*
2004 : * Add vxlan encapsulation. The vxlan id need to be taken
2005 : * from Bridge entry
2006 : */
2007 2 : vr_fmd_set_label(fmd, label, VR_LABEL_TYPE_UNKNOWN);
2008 3 : for (j = 0; j < VR_MAX_PHY_INF; j++) {
2009 3 : if (dir_nh->nh_dev_arr[j] != NULL) {
2010 2 : fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
2011 2 : break;
2012 : }
2013 : }
2014 2 : if (nh_vxlan_tunnel_helper(nh->nh_router, &new_pkt,
2015 2 : fmd, sip, dip) == false) {
2016 0 : PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
2017 0 : vr_pfree(new_pkt, VP_DROP_PUSH);
2018 0 : break;
2019 : }
2020 : }
2021 : }
2022 :
2023 2 : if (nh->nh_family == AF_BRIDGE) {
2024 2 : if (vr_l2_control_data_add(&new_pkt) == false) {
2025 0 : PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
2026 0 : vr_pfree(new_pkt, VP_DROP_PUSH);
2027 0 : break;
2028 : }
2029 2 : vr_fmd_update_l2_control_data(fmd, false);
2030 : }
2031 :
2032 : /* MPLS label for outer header encapsulation */
2033 2 : vr_fmd_set_label(fmd, nh->nh_component_nh[i].cnh_label,
2034 : VR_LABEL_TYPE_UNKNOWN);
2035 3 : for (j = 0; j < VR_MAX_PHY_INF; j++) {
2036 3 : if (dir_nh->nh_dev_arr[j] != NULL) {
2037 2 : fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
2038 2 : break;
2039 : }
2040 : }
2041 2 : nh_output(new_pkt, dir_nh, fmd);
2042 : }
2043 :
2044 : /* Original packet needs to be unconditionally dropped */
2045 2 : drop:
2046 2 : vr_pfree(pkt, drop_reason);
2047 2 : return NH_PROCESSING_COMPLETE;
2048 : }
2049 :
2050 : nh_processing_t
2051 1 : nh_discard(struct vr_packet *pkt, struct vr_nexthop *nh,
2052 : struct vr_forwarding_md *fmd)
2053 : {
2054 1 : struct vr_vrf_stats *stats = NULL;
2055 :
2056 1 : if (vr_inet_vrf_stats) {
2057 1 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
2058 1 : if (stats)
2059 1 : stats->vrf_discards++;
2060 : }
2061 :
2062 1 : PKT_LOG(VP_DROP_DISCARD, pkt, 0, VR_NEXTHOP_C, __LINE__);
2063 1 : vr_pfree(pkt, VP_DROP_DISCARD);
2064 1 : return NH_PROCESSING_COMPLETE;
2065 : }
2066 :
2067 : static uint8_t *
2068 0 : nh_generate_mirroring_sip(struct vr_nexthop *nh,
2069 : struct vr_packet *pkt, struct vr_forwarding_md *fmd)
2070 : {
2071 : uint16_t intf_id;
2072 : mirror_type_t mtype;
2073 0 : struct vr_interface *vif = NULL;
2074 :
2075 0 : mtype = vr_fmd_get_mirror_type(fmd);
2076 :
2077 0 : if (mtype == MIRROR_TYPE_PORT_RX) {
2078 0 : vif = pkt->vp_if;
2079 0 : } else if (mtype == MIRROR_TYPE_PORT_TX) {
2080 0 : intf_id = vr_fmd_get_mirror_if_id(fmd);
2081 0 : if (intf_id != FMD_MIRROR_INVALID_DATA)
2082 0 : vif = __vrouter_get_interface(vrouter_get(nh->nh_rid), intf_id);
2083 : }
2084 :
2085 0 : if (!vif)
2086 0 : return NULL;
2087 :
2088 0 : if (nh->nh_family == AF_INET)
2089 0 : return (uint8_t *)&vif->vif_ip;
2090 0 : else if (nh->nh_family == AF_INET6)
2091 0 : return vif->vif_ip6;
2092 :
2093 0 : return NULL;
2094 : }
2095 :
2096 : static nh_processing_t
2097 1 : nh_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
2098 : struct vr_forwarding_md *fmd)
2099 : {
2100 1 : int ret = -1;
2101 1 : uint8_t *vif_ip = NULL;
2102 1 : uint16_t sport = 0;
2103 : unsigned int head_space, hash;
2104 1 : uint32_t sip = 0, port_range;
2105 : struct vr_packet *tmp;
2106 : struct vr_ip *ip;
2107 : struct vr_ip6 *ip6;
2108 : struct vr_udp *udp;
2109 1 : struct vr_vrf_stats *stats = NULL;
2110 : struct vr_forwarding_class_qos *qos;
2111 1 : struct vr_flow flow, *flowp = &flow;
2112 :
2113 1 : if (!fmd) {
2114 0 : PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
2115 0 : goto send_fail;
2116 : }
2117 :
2118 1 : head_space = sizeof(struct vr_udp) + VR_ETHER_HLEN;
2119 :
2120 1 : if (nh->nh_family == AF_INET)
2121 1 : head_space += sizeof(struct vr_ip);
2122 0 : else if (nh->nh_family == AF_INET6)
2123 0 : head_space += sizeof(struct vr_ip6);
2124 : else {
2125 0 : PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
2126 0 : goto send_fail;
2127 : }
2128 :
2129 1 : if (pkt_head_space(pkt) < head_space) {
2130 0 : tmp = vr_pexpand_head(pkt, head_space - pkt_head_space(pkt));
2131 0 : if (!tmp) {
2132 0 : PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
2133 0 : goto send_fail;
2134 : }
2135 0 : pkt = tmp;
2136 : }
2137 :
2138 1 : if (pkt->vp_type == VP_TYPE_IP) {
2139 1 : ret = vr_inet_get_flow_key(nh->nh_router, pkt, fmd,
2140 : flowp, VR_FLOW_KEY_ALL,
2141 : VR_FRAG_FLAG_MIRROR);
2142 0 : } else if (pkt->vp_type == VP_TYPE_IP6) {
2143 0 : ret = vr_inet6_get_flow_key(nh->nh_router, fmd->fmd_dvrf, pkt,
2144 0 : fmd->fmd_vlan, flowp, VR_FLOW_KEY_ALL,
2145 : VR_FRAG_FLAG_MIRROR);
2146 : }
2147 :
2148 1 : if (!ret) {
2149 1 : hash = vr_hash(flowp, flowp->flow_key_len, 0);
2150 1 : port_range = VR_UDP_PORT_RANGE_END - VR_UDP_PORT_RANGE_START;
2151 1 : sport = (uint16_t)
2152 1 : (((uint64_t ) hash * port_range) >> 32);
2153 1 : sport += VR_UDP_PORT_RANGE_START;
2154 : }
2155 :
2156 1 : if (nh->nh_flags & NH_FLAG_TUNNEL_SIP_COPY) {
2157 0 : vif_ip = nh_generate_mirroring_sip(nh, pkt, fmd);
2158 : }
2159 :
2160 1 : if (nh->nh_family == AF_INET) {
2161 :
2162 1 : if (vif_ip)
2163 0 : sip = *(uint32_t *)vif_ip;
2164 :
2165 1 : if (!sip)
2166 1 : sip = nh->nh_udp_tun_sip;
2167 :
2168 1 : if (!sport)
2169 0 : sport = ntohs(nh->nh_udp_tun_sport);
2170 :
2171 1 : qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
2172 2 : if (nh_udp_tunnel_helper(pkt, htons(sport),
2173 1 : nh->nh_udp_tun_dport, sip,
2174 1 : nh->nh_udp_tun_dip, qos) == false) {
2175 0 : PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
2176 0 : goto send_fail;
2177 : }
2178 :
2179 1 : if (pkt_len(pkt) > ((1 << sizeof(ip->ip_len) * 8))) {
2180 0 : PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
2181 0 : goto send_fail;
2182 : }
2183 :
2184 1 : ip = (struct vr_ip *)(pkt_data(pkt));
2185 1 : udp = (struct vr_udp *)((char *)ip + ip->ip_hl * 4);
2186 1 : udp->udp_csum = vr_ip_partial_csum(ip);
2187 1 : pkt->vp_flags |= VP_FLAG_CSUM_PARTIAL;
2188 :
2189 1 : pkt->vp_type = VP_TYPE_IP;
2190 :
2191 0 : } else if (nh->nh_family == AF_INET6) {
2192 :
2193 0 : if (!sport)
2194 0 : sport = ntohs(nh->nh_udp_tun6_sport);
2195 :
2196 0 : if (nh_udp_tunnel6_helper(pkt, nh, vif_ip, htons(sport),
2197 0 : nh->nh_udp_tun6_dport) == false) {
2198 0 : PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
2199 0 : goto send_fail;
2200 : }
2201 :
2202 0 : ip6 = (struct vr_ip6 *)(pkt_data(pkt));
2203 0 : udp = (struct vr_udp *)((char *)ip6 + sizeof(struct vr_ip6));
2204 0 : udp->udp_csum = vr_ip6_partial_csum(ip6);
2205 0 : pkt->vp_flags |= VP_FLAG_CSUM_PARTIAL;
2206 :
2207 0 : pkt->vp_type = VP_TYPE_IP6;
2208 : }
2209 :
2210 1 : fmd->fmd_udp_src_port = sport;
2211 :
2212 1 : pkt_set_network_header(pkt, pkt->vp_data);
2213 :
2214 : /*
2215 : * Incase of mirroring set the inner network header to the newly added
2216 : * header so that this is fragmented and checksummed
2217 : */
2218 1 : pkt_set_inner_network_header(pkt, pkt->vp_data);
2219 :
2220 1 : if (vr_inet_vrf_stats) {
2221 1 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
2222 1 : if (stats)
2223 1 : stats->vrf_udp_tunnels++;
2224 : }
2225 :
2226 1 : vr_forward(vrouter_get(nh->nh_rid), pkt, fmd);
2227 :
2228 1 : return NH_PROCESSING_COMPLETE;
2229 :
2230 0 : send_fail:
2231 0 : vr_pfree(pkt, VP_DROP_PUSH);
2232 0 : return NH_PROCESSING_COMPLETE;
2233 : }
2234 :
2235 : /*
2236 : * nh_vxlan_tunnel - tunnel packet with VXLAN header
2237 : */
2238 : static nh_processing_t
2239 6 : nh_vxlan_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
2240 : struct vr_forwarding_md *fmd)
2241 : {
2242 : struct vr_interface *vif;
2243 6 : struct vr_vrf_stats *stats = NULL;
2244 6 : unsigned short reason = VP_DROP_PUSH;
2245 : struct vr_packet *tmp_pkt;
2246 : struct vr_df_trap_arg trap_arg;
2247 : unsigned short overhead_len;
2248 :
2249 6 : if (!fmd) {
2250 0 : reason = VP_DROP_NO_FMD;
2251 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2252 0 : goto send_fail;
2253 : }
2254 :
2255 6 : if (fmd->fmd_label < 0) {
2256 0 : reason = VP_DROP_INVALID_LABEL;
2257 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2258 0 : goto send_fail;
2259 : }
2260 :
2261 6 : if (vr_inet_vrf_stats) {
2262 6 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
2263 6 : if (stats)
2264 6 : stats->vrf_vxlan_tunnels++;
2265 : }
2266 :
2267 6 : if (nh_tunnel_loop_detect_handle(pkt, nh, fmd, nh->nh_vxlan_tun_dip))
2268 0 : return NH_PROCESSING_COMPLETE;
2269 :
2270 6 : if (vr_perfs)
2271 6 : pkt->vp_flags |= VP_FLAG_GSO;
2272 :
2273 : /* Assigning the vif */
2274 6 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
2275 1 : vif = nh_underlay_tunnel_vif_selection(pkt, fmd, nh, &reason);
2276 1 : if (reason == VP_DROP_INVALID_UNDERLAY_ECMP && !vif) {
2277 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2278 0 : goto send_fail;
2279 : }
2280 : } else
2281 5 : vif = nh->nh_dev;
2282 :
2283 6 : if (nh->nh_flags & NH_FLAG_L3_VXLAN) {
2284 : struct vr_eth *eth;
2285 :
2286 : /* Preset the pkt to make it point to L2 header */
2287 0 : vr_preset(pkt);
2288 :
2289 0 : if (!vif || IS_MAC_ZERO(vif->vif_mac)) {
2290 0 : reason = VP_DROP_INTERFACE_DROP;
2291 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2292 0 : goto send_fail;
2293 : }
2294 :
2295 0 : eth = (struct vr_eth *)pkt_data(pkt);
2296 0 : VR_MAC_COPY(eth->eth_dmac, nh->nh_vxlan_tun_l3_mac);
2297 0 : VR_MAC_COPY(eth->eth_smac, vif->vif_mac);
2298 : }
2299 :
2300 6 : overhead_len = VR_VXLAN_HDR_LEN;
2301 6 : if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
2302 6 : if (vr_has_to_fragment(vif, pkt, overhead_len) &&
2303 0 : vr_ip_dont_fragment_set(pkt)) {
2304 0 : if (pkt->vp_flags & VP_FLAG_MULTICAST) {
2305 0 : reason = VP_DROP_MCAST_DF_BIT;
2306 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2307 0 : goto send_fail;
2308 : }
2309 :
2310 0 : trap_arg.df_mtu = vif_get_mtu(vif) -
2311 0 : (overhead_len + pkt_get_network_header_off(pkt) - pkt->vp_data);
2312 0 : trap_arg.df_flow_index = fmd->fmd_flow_index;
2313 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_HANDLE_DF, (void *)&trap_arg);
2314 0 : return NH_PROCESSING_COMPLETE;
2315 : }
2316 : }
2317 :
2318 6 : if (nh_vxlan_tunnel_helper(nh->nh_router, &pkt, fmd, nh->nh_vxlan_tun_sip,
2319 6 : nh->nh_vxlan_tun_dip) == false)
2320 0 : goto send_fail;
2321 :
2322 6 : pkt_set_network_header(pkt, pkt->vp_data);
2323 :
2324 6 : if (pkt->vp_type == VP_TYPE_IPOIP)
2325 0 : pkt->vp_type = VP_TYPE_IP;
2326 6 : else if (pkt->vp_type == VP_TYPE_IP6OIP)
2327 0 : pkt->vp_type = VP_TYPE_IP6;
2328 :
2329 : /*
2330 : * Change the packet type
2331 : */
2332 6 : if (pkt->vp_type == VP_TYPE_IP6)
2333 3 : pkt->vp_type = VP_TYPE_IP6OIP;
2334 3 : else if (pkt->vp_type == VP_TYPE_IP)
2335 3 : pkt->vp_type = VP_TYPE_IPOIP;
2336 : else
2337 0 : pkt->vp_type = VP_TYPE_IP;
2338 :
2339 6 : if (pkt_head_space(pkt) < nh->nh_vxlan_tun_encap_len) {
2340 0 : tmp_pkt = vr_pexpand_head(pkt, nh->nh_vxlan_tun_encap_len - pkt_head_space(pkt));
2341 0 : if (!tmp_pkt) {
2342 0 : goto send_fail;
2343 : }
2344 0 : pkt = tmp_pkt;
2345 : }
2346 :
2347 : /* slap l2 header */
2348 6 : if (nh->nh_flags & NH_FLAG_CRYPT_TRAFFIC) {
2349 0 : if (!nh->nh_crypt_dev) {
2350 0 : reason = VP_DROP_NO_CRYPT_PATH;
2351 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2352 0 : goto send_fail;
2353 : }
2354 0 : vif = nh->nh_crypt_dev;
2355 : }
2356 : /*
2357 : * during l3 multihoming, the nh_data passed can contain encap data from
2358 : * multiple gateways. To ensure that the right data is passed, the nh_data
2359 : * pointer is shifted to the relevant encap data address using the product
2360 : * of len of data and the vif_idx which the physical interface corresponding
2361 : * to the encap data. Since physical interfaces will always have the Id 0, 1
2362 : * or 2, vif_idx can directly be used.
2363 : */
2364 6 : if (vif_is_fabric(vif) && (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP)) {
2365 1 : if (vif->vif_set_rewrite(vif, &pkt, fmd,
2366 1 : (nh->nh_data +(nh->nh_vxlan_tun_encap_len * vif->vif_idx)),
2367 1 : nh->nh_vxlan_tun_encap_len) < 0) {
2368 0 : goto send_fail;
2369 : }
2370 : } else {
2371 5 : if (vif->vif_set_rewrite(vif, &pkt, fmd,
2372 5 : nh->nh_data, nh->nh_vxlan_tun_encap_len) < 0) {
2373 0 : goto send_fail;
2374 : }
2375 : }
2376 :
2377 6 : vif->vif_tx(vif, pkt, fmd);
2378 :
2379 6 : return NH_PROCESSING_COMPLETE;
2380 :
2381 0 : send_fail:
2382 0 : vr_pfree(pkt, reason);
2383 0 : return NH_PROCESSING_COMPLETE;
2384 :
2385 : }
2386 :
2387 : static nh_processing_t
2388 0 : nh_pbb_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
2389 : struct vr_forwarding_md *fmd)
2390 : {
2391 0 : struct vr_vrf_stats *stats = NULL;
2392 :
2393 0 : if (vr_fmd_etree_is_enabled(fmd)) {
2394 0 : if ((!vr_fmd_etree_is_root(fmd)) &&
2395 0 : (!(nh->nh_flags & NH_FLAG_ETREE_ROOT))) {
2396 0 : PKT_LOG(VP_DROP_LEAF_TO_LEAF, pkt, 0, VR_NEXTHOP_C, __LINE__);
2397 0 : vr_pfree(pkt, VP_DROP_LEAF_TO_LEAF);
2398 0 : return NH_PROCESSING_COMPLETE;
2399 : }
2400 : }
2401 :
2402 0 : if (vr_inet_vrf_stats) {
2403 0 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
2404 0 : if (stats)
2405 0 : stats->vrf_pbb_tunnels++;
2406 : }
2407 :
2408 0 : if (!nh_pbb_tunnel_helper(nh->nh_router, &pkt, fmd, nh->nh_pbb_mac,
2409 0 : pkt->vp_if->vif_pbb_mac, pkt->vp_if->vif_isid)) {
2410 0 : PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
2411 0 : vr_pfree(pkt, VP_DROP_PUSH);
2412 0 : return NH_PROCESSING_COMPLETE;
2413 : }
2414 0 : vr_fmd_set_label(fmd, nh->nh_pbb_label, VR_LABEL_TYPE_UNKNOWN);
2415 :
2416 0 : return NH_PROCESSING_INCOMPLETE;
2417 : }
2418 :
2419 : static int
2420 0 : nh_pbb_tunnel_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
2421 : struct vr_forwarding_md *fmd, void *ret_data)
2422 : {
2423 0 : bool root = false;
2424 :
2425 0 : if (nh->nh_flags & NH_FLAG_ETREE_ROOT)
2426 0 : root = true;
2427 0 : vr_fmd_update_etree_root(fmd,root);
2428 :
2429 0 : if (VR_MAC_CMP(nh->nh_pbb_mac, fmd->fmd_smac)) {
2430 0 : return NH_SOURCE_VALID;
2431 : }
2432 :
2433 0 : return NH_SOURCE_INVALID;
2434 : }
2435 :
2436 : static int
2437 7 : nh_mpls_udp_tunnel_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
2438 : struct vr_forwarding_md *fmd, void *ret_data)
2439 : {
2440 7 : if (fmd->fmd_outer_src_ip == nh->nh_udp_tun_dip)
2441 5 : return NH_SOURCE_VALID;
2442 :
2443 2 : return NH_SOURCE_INVALID;
2444 : }
2445 :
2446 : static int
2447 0 : nh_vxlan_tunnel_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
2448 : struct vr_forwarding_md *fmd, void *ret_data)
2449 : {
2450 0 : if (fmd->fmd_outer_src_ip == nh->nh_udp_tun_dip)
2451 0 : return NH_SOURCE_VALID;
2452 :
2453 0 : return NH_SOURCE_INVALID;
2454 : }
2455 :
2456 :
2457 : /*
2458 : * nh_mpls_udp_tunnel - tunnel packet with MPLS label in UDP.
2459 : */
2460 : static nh_processing_t
2461 51 : nh_mpls_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
2462 : struct vr_forwarding_md *fmd)
2463 : {
2464 : unsigned int tun_sip, tun_dip, overhead_len, mudp_head_space;
2465 51 : uint16_t tun_encap_len, udp_src_port = VR_MPLS_OVER_UDP_SRC_PORT;
2466 51 : unsigned short reason = VP_DROP_PUSH;
2467 :
2468 : int tun_encap_rewrite;
2469 : struct vr_forwarding_class_qos *qos;
2470 : struct vr_interface *vif;
2471 51 : struct vr_vrf_stats *stats = NULL;
2472 : struct vr_packet *tmp_pkt;
2473 : struct vr_df_trap_arg trap_arg;
2474 51 : unsigned int label_count = 0;
2475 51 : uint32_t transport_label = 0;
2476 :
2477 : /*
2478 : * If we are testing MPLS over UDP using the vr_mudp sysctl, use the
2479 : * values from the GRE tunnel nexthop below. Otherwise, use the values
2480 : * from the UDP tunnel nexthop.
2481 : */
2482 51 : if (vr_mudp) {
2483 0 : tun_sip = nh->nh_gre_tun_sip;
2484 0 : tun_dip = nh->nh_gre_tun_dip;
2485 0 : tun_encap_len = nh->nh_gre_tun_encap_len;
2486 : } else {
2487 51 : tun_sip = nh->nh_udp_tun_sip;
2488 51 : tun_dip = nh->nh_udp_tun_dip;
2489 51 : tun_encap_len = nh->nh_udp_tun_encap_len;
2490 51 : transport_label = nh->nh_udp_tun_label;
2491 : }
2492 :
2493 51 : if (vr_inet_vrf_stats) {
2494 51 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
2495 51 : if (stats) {
2496 51 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
2497 0 : stats->vrf_udp_mpls_over_mpls_tunnels++;
2498 : } else {
2499 51 : stats->vrf_udp_mpls_tunnels++;
2500 : }
2501 : }
2502 : }
2503 :
2504 51 : if (!fmd || fmd->fmd_label < 0) {
2505 0 : vr_forward(nh->nh_router, pkt, fmd);
2506 0 : return NH_PROCESSING_COMPLETE;
2507 : }
2508 :
2509 51 : vr_fmd_update_label_type(fmd, VR_LABEL_TYPE_MPLS);
2510 :
2511 51 : if (nh_tunnel_loop_detect_handle(pkt, nh, fmd, tun_dip))
2512 0 : return NH_PROCESSING_COMPLETE;
2513 :
2514 51 : if (fmd->fmd_udp_src_port)
2515 19 : udp_src_port = fmd->fmd_udp_src_port;
2516 :
2517 : /*
2518 : * The UDP source port is a hash of the inner IP src/dst address and
2519 : * vrf.
2520 : */
2521 51 : if ((!fmd->fmd_udp_src_port) && vr_get_udp_src_port) {
2522 32 : udp_src_port = vr_get_udp_src_port(pkt, fmd, fmd->fmd_dvrf);
2523 32 : if (udp_src_port == 0) {
2524 0 : reason = VP_DROP_PULL;
2525 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2526 0 : goto send_fail;
2527 : }
2528 : }
2529 :
2530 51 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
2531 0 : label_count = 2;
2532 : } else {
2533 51 : label_count = 1;
2534 : }
2535 : /* Calculate the head space for mpls,udp ip and eth */
2536 51 : mudp_head_space = (label_count*VR_MPLS_HDR_LEN) +
2537 51 : sizeof(struct vr_ip) + sizeof(struct vr_udp);
2538 51 : if (vr_fmd_l2_control_data_is_enabled(fmd))
2539 0 : mudp_head_space += VR_L2_CTRL_DATA_LEN;
2540 :
2541 : /* Assigning the vif */
2542 51 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
2543 5 : vif = nh_underlay_tunnel_vif_selection(pkt, fmd, nh, &reason);
2544 5 : if (reason == VP_DROP_INVALID_UNDERLAY_ECMP && !vif) {
2545 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2546 0 : goto send_fail;
2547 : }
2548 : } else
2549 46 : vif = nh->nh_dev;
2550 :
2551 51 : if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
2552 49 : overhead_len = mudp_head_space;
2553 50 : if (vr_has_to_fragment(vif, pkt, overhead_len) &&
2554 1 : vr_ip_dont_fragment_set(pkt)) {
2555 0 : if (pkt->vp_flags & VP_FLAG_MULTICAST) {
2556 0 : reason = VP_DROP_MCAST_DF_BIT;
2557 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2558 0 : goto send_fail;
2559 : }
2560 0 : trap_arg.df_mtu = vif_get_mtu(vif) -
2561 0 : (overhead_len + pkt_get_network_header_off(pkt) - pkt->vp_data);
2562 0 : trap_arg.df_flow_index = fmd->fmd_flow_index;
2563 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_HANDLE_DF, (void *)&trap_arg);
2564 0 : return NH_PROCESSING_COMPLETE;
2565 : }
2566 : }
2567 :
2568 51 : mudp_head_space += tun_encap_len;
2569 :
2570 51 : if (pkt_head_space(pkt) < mudp_head_space) {
2571 0 : tmp_pkt = vr_pexpand_head(pkt, mudp_head_space - pkt_head_space(pkt));
2572 0 : if (!tmp_pkt)
2573 0 : goto send_fail;
2574 :
2575 0 : pkt = tmp_pkt;
2576 : }
2577 :
2578 51 : if (vr_fmd_l2_control_data_is_enabled(fmd)) {
2579 0 : if (!vr_l2_control_data_add(&pkt))
2580 0 : goto send_fail;
2581 : }
2582 :
2583 51 : qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
2584 51 : if (nh_push_mpls_header(pkt, fmd->fmd_label, qos, true) < 0) {
2585 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2586 0 : goto send_fail;
2587 : }
2588 51 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
2589 : /* insert outer label (transport label) */
2590 0 : if (nh_push_mpls_header(pkt, transport_label, qos, false) < 0) {
2591 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2592 0 : goto send_fail;
2593 : }
2594 : }
2595 :
2596 :
2597 51 : if (vr_perfs)
2598 51 : pkt->vp_flags |= VP_FLAG_GSO;
2599 :
2600 :
2601 51 : if (pkt->vp_type == VP_TYPE_IPOIP)
2602 0 : pkt->vp_type = VP_TYPE_IP;
2603 51 : else if (pkt->vp_type == VP_TYPE_IP6OIP)
2604 0 : pkt->vp_type = VP_TYPE_IP6;
2605 :
2606 : /*
2607 : * Change the packet type
2608 : */
2609 51 : if (pkt->vp_type == VP_TYPE_IP6)
2610 2 : pkt->vp_type = VP_TYPE_IP6OIP;
2611 49 : else if (pkt->vp_type == VP_TYPE_IP)
2612 47 : pkt->vp_type = VP_TYPE_IPOIP;
2613 : else
2614 2 : pkt->vp_type = VP_TYPE_IP;
2615 :
2616 102 : if (nh_udp_tunnel_helper(pkt, htons(udp_src_port),
2617 51 : htons(VR_MPLS_OVER_UDP_DST_PORT),
2618 51 : tun_sip, tun_dip, qos) == false) {
2619 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2620 0 : goto send_fail;
2621 : }
2622 :
2623 51 : pkt_set_network_header(pkt, pkt->vp_data);
2624 :
2625 : /* slap l2 header */
2626 51 : if (nh->nh_flags & NH_FLAG_CRYPT_TRAFFIC) {
2627 0 : if (!nh->nh_crypt_dev) {
2628 0 : reason = VP_DROP_NO_CRYPT_PATH;
2629 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2630 0 : goto send_fail;
2631 : }
2632 0 : vif = nh->nh_crypt_dev;
2633 : }
2634 : /*
2635 : * during l3 multihoming, the nh_data passed can contain encap data from
2636 : * multiple gateways. To ensure that the right data is passed, the nh_data
2637 : * pointer is shifted to the relevant encap data address using the product
2638 : * of len of data and the vif_idx which the physical interface corresponding
2639 : * to the encap data. Since physical interfaces will always have the Id 0,
2640 : * 1 or 2, vif_idx can directly be used.
2641 : */
2642 51 : if (vif_is_fabric(vif) && (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP)) {
2643 5 : tun_encap_rewrite = vif->vif_set_rewrite(vif, &pkt, fmd,
2644 5 : (nh->nh_data + (tun_encap_len * vif->vif_idx)), tun_encap_len);
2645 : } else {
2646 46 : tun_encap_rewrite = vif->vif_set_rewrite(vif, &pkt, fmd,
2647 46 : nh->nh_data, tun_encap_len);
2648 : }
2649 51 : if (tun_encap_rewrite < 0) {
2650 0 : reason = VP_DROP_REWRITE_FAIL;
2651 0 : PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2652 0 : goto send_fail;
2653 : }
2654 :
2655 51 : vif->vif_tx(vif, pkt, fmd);
2656 :
2657 51 : return NH_PROCESSING_COMPLETE;
2658 :
2659 0 : send_fail:
2660 0 : vr_pfree(pkt, reason);
2661 0 : return NH_PROCESSING_COMPLETE;
2662 :
2663 : }
2664 :
2665 : static int
2666 0 : nh_gre_tunnel_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
2667 : struct vr_forwarding_md *fmd, void *ret_data)
2668 : {
2669 0 : if (fmd->fmd_outer_src_ip == nh->nh_gre_tun_dip)
2670 0 : return NH_SOURCE_VALID;
2671 :
2672 0 : return NH_SOURCE_INVALID;
2673 : }
2674 :
2675 : static nh_processing_t
2676 6 : nh_gre_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
2677 : struct vr_forwarding_md *fmd)
2678 : {
2679 : int overhead_len, gre_head_space;
2680 6 : unsigned short drop_reason = VP_DROP_INVALID_NH;
2681 : unsigned int id;
2682 :
2683 : int tun_encap_rewrite;
2684 : struct vr_forwarding_class_qos *qos;
2685 : struct vr_gre *gre_hdr;
2686 : struct vr_ip *ip;
2687 : struct vr_interface *vif;
2688 6 : struct vr_vrf_stats *stats = NULL;
2689 : struct vr_packet *tmp_pkt;
2690 : struct vr_df_trap_arg trap_arg;
2691 6 : unsigned int label_count = 0;
2692 :
2693 6 : if (vr_mudp && vr_perfs) {
2694 0 : return nh_mpls_udp_tunnel(pkt, nh, fmd);
2695 : }
2696 :
2697 6 : if (vr_inet_vrf_stats) {
2698 6 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
2699 6 : if (stats) {
2700 6 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
2701 0 : stats->vrf_udp_mpls_over_mpls_tunnels++;
2702 : } else {
2703 6 : stats->vrf_gre_mpls_tunnels++;
2704 : }
2705 : }
2706 : }
2707 :
2708 : /*
2709 : * When the packet encounters a tunnel nexthop with policy enabled,
2710 : * the forwarding metadata (and hence the label filled up by vr_forward)
2711 : * is lost as packets are queued in the flow entry. Note also the fact
2712 : * that nh_output sets pkt->vp_nh to the looked up NH. So, once the
2713 : * flow queue is flushed, we will not do vr_forward again and hence we
2714 : * will not have label information. For those packets, we need to do
2715 : * vr_forward again. One practical example of where this can happen is
2716 : * when ECMP source initiates traffic to a target in a remote (not in
2717 : * the same) server. vr_forward->tunnel_nh->nh_output sets pkt->vp_nh
2718 : * (source is ECMP)->pass through flow lookup->
2719 : */
2720 6 : if (!fmd || fmd->fmd_label < 0) {
2721 0 : vr_forward(nh->nh_router, pkt, fmd);
2722 0 : return NH_PROCESSING_COMPLETE;
2723 : }
2724 :
2725 6 : vr_fmd_update_label_type(fmd, VR_LABEL_TYPE_MPLS);
2726 :
2727 6 : if (nh_tunnel_loop_detect_handle(pkt, nh, fmd, nh->nh_gre_tun_dip))
2728 0 : return NH_PROCESSING_COMPLETE;
2729 :
2730 6 : if (vr_perfs)
2731 6 : pkt->vp_flags |= VP_FLAG_GSO;
2732 :
2733 6 : if (pkt->vp_type == VP_TYPE_IP) {
2734 4 : ip = (struct vr_ip *)pkt_network_header(pkt);
2735 4 : id = ip->ip_id;
2736 : } else {
2737 2 : id = htons(vr_generate_unique_ip_id());
2738 : }
2739 :
2740 6 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
2741 0 : label_count = 2;
2742 : } else {
2743 6 : label_count = 1;
2744 : }
2745 :
2746 6 : gre_head_space = (label_count *VR_MPLS_HDR_LEN) + sizeof(struct vr_ip) +
2747 : sizeof(struct vr_gre);
2748 6 : if (vr_fmd_l2_control_data_is_enabled(fmd))
2749 0 : gre_head_space += VR_L2_CTRL_DATA_LEN;
2750 :
2751 : /* Assigning the vif */
2752 6 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
2753 2 : vif = nh_underlay_tunnel_vif_selection(pkt, fmd, nh, &drop_reason);
2754 2 : if (drop_reason == VP_DROP_INVALID_UNDERLAY_ECMP && !vif) {
2755 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2756 0 : goto send_fail;
2757 : }
2758 : } else
2759 4 : vif = nh->nh_dev;
2760 :
2761 6 : if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
2762 : /*
2763 : * If there are any L2 headers lets add those as well. For L3
2764 : * unicast, following will add no extra overhead
2765 : */
2766 6 : overhead_len = gre_head_space;
2767 6 : if (vr_has_to_fragment(vif, pkt, overhead_len) &&
2768 0 : vr_ip_dont_fragment_set(pkt)) {
2769 0 : if (pkt->vp_flags & VP_FLAG_MULTICAST) {
2770 0 : drop_reason = VP_DROP_MCAST_DF_BIT;
2771 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2772 0 : goto send_fail;
2773 : }
2774 :
2775 0 : trap_arg.df_mtu = vif_get_mtu(vif) -
2776 0 : (overhead_len + pkt_get_network_header_off(pkt) - pkt->vp_data);
2777 0 : trap_arg.df_flow_index = fmd->fmd_flow_index;
2778 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_HANDLE_DF, (void *)&trap_arg);
2779 0 : return NH_PROCESSING_COMPLETE;
2780 : }
2781 : }
2782 :
2783 6 : gre_head_space += nh->nh_gre_tun_encap_len;
2784 :
2785 6 : if (pkt_head_space(pkt) < gre_head_space) {
2786 0 : tmp_pkt = vr_pexpand_head(pkt, gre_head_space - pkt_head_space(pkt));
2787 0 : if (!tmp_pkt) {
2788 0 : drop_reason = VP_DROP_HEAD_ALLOC_FAIL;
2789 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2790 0 : goto send_fail;
2791 : }
2792 0 : pkt = tmp_pkt;
2793 : }
2794 :
2795 6 : if (vr_fmd_l2_control_data_is_enabled(fmd)) {
2796 0 : if (!vr_l2_control_data_add(&pkt))
2797 0 : goto send_fail;
2798 : }
2799 :
2800 6 : qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
2801 6 : if (nh_push_mpls_header(pkt, fmd->fmd_label, qos, true) < 0)
2802 0 : goto send_fail;
2803 6 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
2804 : /* insert outer label (transport label) */
2805 0 : if (nh_push_mpls_header(pkt, nh->nh_gre_tun_label, qos, false) < 0)
2806 0 : goto send_fail;
2807 : }
2808 :
2809 6 : gre_hdr = (struct vr_gre *)pkt_push(pkt, sizeof(struct vr_gre));
2810 6 : if (!gre_hdr) {
2811 0 : drop_reason = VP_DROP_PUSH;
2812 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2813 0 : goto send_fail;
2814 : }
2815 :
2816 6 : gre_hdr->gre_flags = 0;
2817 6 : gre_hdr->gre_proto = VR_GRE_PROTO_MPLS_NO;
2818 :
2819 6 : ip = (struct vr_ip *)pkt_push(pkt, sizeof(struct vr_ip));
2820 6 : if (!ip) {
2821 0 : drop_reason = VP_DROP_PUSH;
2822 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2823 0 : goto send_fail;
2824 : }
2825 6 : pkt_set_network_header(pkt, pkt->vp_data);
2826 :
2827 6 : if (pkt->vp_type == VP_TYPE_IPOIP)
2828 0 : pkt->vp_type = VP_TYPE_IP;
2829 6 : else if (pkt->vp_type == VP_TYPE_IP6OIP)
2830 0 : pkt->vp_type = VP_TYPE_IP6;
2831 :
2832 6 : if (pkt->vp_type == VP_TYPE_IP6)
2833 2 : pkt->vp_type = VP_TYPE_IP6OIP;
2834 4 : else if (pkt->vp_type == VP_TYPE_IP)
2835 4 : pkt->vp_type = VP_TYPE_IPOIP;
2836 : else
2837 0 : pkt->vp_type = VP_TYPE_IP;
2838 :
2839 6 : ip->ip_version = 4;
2840 6 : ip->ip_hl = 5;
2841 6 : if (qos) {
2842 0 : ip->ip_tos = VR_IP_DSCP(qos->vfcq_dscp);
2843 0 : pkt->vp_queue = qos->vfcq_queue_id;
2844 0 : pkt->vp_priority = qos->vfcq_dotonep_qos;
2845 : } else {
2846 6 : ip->ip_tos = 0;
2847 : }
2848 :
2849 6 : ip->ip_id = id;
2850 6 : ip->ip_frag_off = 0;
2851 :
2852 6 : if (vr_pkt_is_diag(pkt)) {
2853 0 : ip->ip_ttl = pkt->vp_ttl;
2854 : } else {
2855 6 : ip->ip_ttl = 64;
2856 : }
2857 :
2858 6 : ip->ip_proto = VR_IP_PROTO_GRE;
2859 6 : ip->ip_saddr = nh->nh_gre_tun_sip;
2860 6 : ip->ip_daddr = nh->nh_gre_tun_dip;
2861 6 : ip->ip_len = htons(pkt_len(pkt));
2862 : /* checksum will be calculated for tunneled packet in linux_xmit_segment */
2863 6 : if (!vr_pkt_type_is_overlay(pkt->vp_type)) {
2864 0 : ip->ip_csum = 0;
2865 0 : ip->ip_csum = vr_ip_csum(ip);
2866 : }
2867 :
2868 : /* slap l2 header */
2869 6 : if (nh->nh_flags & NH_FLAG_CRYPT_TRAFFIC) {
2870 0 : if (!nh->nh_crypt_dev) {
2871 0 : drop_reason = VP_DROP_NO_CRYPT_PATH;
2872 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2873 0 : goto send_fail;
2874 : }
2875 0 : vif = nh->nh_crypt_dev;
2876 : }
2877 : /*
2878 : * during l3 multihoming, the nh_data passed can contain encap data from
2879 : * multiple gateways. To ensure that the right data is passed, the nh_data
2880 : * pointer is shifted to the relevant encap data address using the product
2881 : * of len of data and the vif_idx which the physical interface corresponding
2882 : * to the encap data. Since physical interfaces will always have the Id 0,
2883 : * 1 or 2, vif_idx can directly be used.
2884 : */
2885 6 : if (vif_is_fabric(vif) && (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP)) {
2886 2 : tun_encap_rewrite = vif->vif_set_rewrite(vif, &pkt, fmd,
2887 2 : (nh->nh_data + (nh->nh_gre_tun_encap_len * vif->vif_idx)),
2888 2 : nh->nh_gre_tun_encap_len);
2889 : } else {
2890 4 : tun_encap_rewrite = vif->vif_set_rewrite(vif, &pkt, fmd,
2891 4 : nh->nh_data, nh->nh_gre_tun_encap_len);
2892 : }
2893 6 : if (tun_encap_rewrite < 0) {
2894 0 : drop_reason = VP_DROP_REWRITE_FAIL;
2895 0 : PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
2896 0 : goto send_fail;
2897 : }
2898 6 : vif->vif_tx(vif, pkt, fmd);
2899 6 : return NH_PROCESSING_COMPLETE;
2900 :
2901 0 : send_fail:
2902 0 : vr_pfree(pkt, drop_reason);
2903 0 : return NH_PROCESSING_COMPLETE;
2904 : }
2905 :
2906 :
2907 : /*
2908 : * Returns 0 - Completion of pkt handling
2909 : * <0 - Error in pkt handling
2910 : */
2911 : int
2912 180 : nh_output(struct vr_packet *pkt, struct vr_nexthop *nh,
2913 : struct vr_forwarding_md *fmd)
2914 : {
2915 180 : bool need_flow_lookup = false;
2916 : nh_processing_t res;
2917 :
2918 180 : if (!pkt->vp_ttl) {
2919 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ZERO_TTL, NULL);
2920 0 : return 0;
2921 : }
2922 :
2923 180 : pkt->vp_nh = nh;
2924 :
2925 :
2926 : /* If nexthop does not have valid data, drop it */
2927 180 : if (!(nh->nh_flags & NH_FLAG_VALID)) {
2928 0 : PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_NEXTHOP_C, __LINE__);
2929 0 : vr_pfree(pkt, VP_DROP_INVALID_NH);
2930 0 : return 0;
2931 : }
2932 :
2933 180 : if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
2934 : /*
2935 : * If the packet has not gone through flow lookup once
2936 : * (!VP_FLAG_FLOW_SET), we need to determine whether it has to undergo
2937 : * flow lookup now or not. There are two cases:
2938 : *
2939 : * 1. when policy flag is set in the nexthop, and
2940 : * 2. when the source is an ECMP (For bridged packets this ECMP
2941 : * is avoided)
2942 : *
2943 : * When the source is an ECMP, we would like the packet to reach the
2944 : * same place from where it came from, and hence a flow has to be setup
2945 : * so that DP knows where to send the packet to (from an ECMP NH).
2946 : * Typical example for this situation is when the packet reaches the
2947 : * target VM's server from an ECMP-ed service chain.
2948 : */
2949 177 : if (!(pkt->vp_flags & VP_FLAG_FLOW_SET)) {
2950 97 : if (nh->nh_flags & (NH_FLAG_POLICY_ENABLED |
2951 : NH_FLAG_FLOW_LOOKUP)) {
2952 14 : need_flow_lookup = true;
2953 : }
2954 :
2955 97 : if (need_flow_lookup) {
2956 14 : pkt->vp_flags |= VP_FLAG_FLOW_GET;
2957 : /*
2958 : * after vr_flow_forward returns, pkt->vp_nh could have changed
2959 : * since in NAT cases the new destination should have been
2960 : * looked up.
2961 : */
2962 14 : if (!vr_flow_forward(nh->nh_router, pkt, fmd))
2963 4 : return 0;
2964 :
2965 : /* pkt->vp_nh could have changed after vr_flow_forward */
2966 10 : if (!pkt->vp_nh) {
2967 0 : PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_NEXTHOP_C, __LINE__);
2968 0 : vr_pfree(pkt, VP_DROP_INVALID_NH);
2969 0 : return 0;
2970 : }
2971 :
2972 10 : if (nh != pkt->vp_nh) {
2973 0 : return nh_output(pkt, pkt->vp_nh, fmd);
2974 : }
2975 : }
2976 : }
2977 : }
2978 :
2979 176 : res = nh->nh_reach_nh(pkt, nh, fmd);
2980 176 : if (res == NH_PROCESSING_COMPLETE)
2981 176 : return 0;
2982 :
2983 0 : if ((nh->nh_flags & NH_FLAG_INDIRECT) && nh->nh_direct_nh)
2984 0 : return nh_output(pkt, nh->nh_direct_nh, fmd);
2985 : else
2986 0 : vr_pfree(pkt, VP_DROP_INVALID_NH);
2987 :
2988 0 : return 0;
2989 : }
2990 :
2991 : static nh_processing_t
2992 14 : nh_encap_l2(struct vr_packet *pkt, struct vr_nexthop *nh,
2993 : struct vr_forwarding_md *fmd)
2994 : {
2995 14 : int8_t eth_mac[VR_ETHER_ALEN], *pbb_self_mac = eth_mac;
2996 : struct vr_interface *vif;
2997 14 : struct vr_vrf_stats *stats = NULL;
2998 : struct vr_forwarding_class_qos *qos;
2999 :
3000 14 : if (vr_fmd_etree_is_enabled(fmd)) {
3001 0 : if ((!vr_fmd_etree_is_root(fmd)) &&
3002 0 : (!(nh->nh_flags & NH_FLAG_ETREE_ROOT))) {
3003 0 : PKT_LOG(VP_DROP_LEAF_TO_LEAF, pkt, 0, VR_NEXTHOP_C, __LINE__);
3004 0 : vr_pfree(pkt, VP_DROP_LEAF_TO_LEAF);
3005 0 : return NH_PROCESSING_COMPLETE;
3006 : }
3007 : }
3008 :
3009 : /* No GRO for multicast and user packets */
3010 14 : if ((pkt->vp_flags & VP_FLAG_MULTICAST) ||
3011 14 : (fmd->fmd_vlan != VLAN_ID_INVALID)) {
3012 5 : vr_pkt_unset_gro(pkt);
3013 : }
3014 :
3015 14 : vif = nh->nh_dev;
3016 14 : if (!vif) {
3017 0 : PKT_LOG(VP_DROP_INVALID_IF, pkt, 0, VR_NEXTHOP_C, __LINE__);
3018 0 : vr_pfree(pkt, VP_DROP_INVALID_IF);
3019 0 : return NH_PROCESSING_COMPLETE;
3020 : }
3021 :
3022 14 : if (!IS_MAC_ZERO(fmd->fmd_dmac) &&
3023 0 : !IS_MAC_ZERO(vif->vif_pbb_mac)) {
3024 :
3025 0 : if (IS_MAC_BMCAST(fmd->fmd_dmac))
3026 0 : vr_mcast_mac_from_isid(vif->vif_isid, pbb_self_mac);
3027 : else
3028 0 : pbb_self_mac = vif->vif_pbb_mac;
3029 :
3030 0 : if (!VR_MAC_CMP(fmd->fmd_dmac, pbb_self_mac)) {
3031 0 : PKT_LOG(VP_DROP_BMAC_ISID_MISMATCH, pkt, 0, VR_NEXTHOP_C, __LINE__);
3032 0 : vr_pfree(pkt, VP_DROP_BMAC_ISID_MISMATCH);
3033 0 : return NH_PROCESSING_COMPLETE;
3034 : }
3035 : }
3036 :
3037 14 : if (vr_inet_vrf_stats)
3038 14 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
3039 :
3040 14 : if (vif_is_fabric(vif)) {
3041 0 : if (!(pkt->vp_flags & VP_FLAG_GROED)) {
3042 0 : qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
3043 0 : if (qos) {
3044 0 : if (pkt->vp_type == VP_TYPE_IP) {
3045 0 : vr_inet_set_tos((struct vr_ip *)pkt_network_header(pkt),
3046 0 : VR_IP_DSCP(qos->vfcq_dscp));
3047 0 : } else if (pkt->vp_type == VP_TYPE_IP6) {
3048 0 : vr_inet6_set_tos((struct vr_ip6 *)pkt_network_header(pkt),
3049 0 : qos->vfcq_dscp);
3050 : }
3051 0 : pkt->vp_queue = qos->vfcq_queue_id;
3052 0 : pkt->vp_priority = qos->vfcq_dotonep_qos;
3053 : }
3054 : }
3055 : }
3056 :
3057 14 : if (vr_pkt_is_gro(pkt) && vif_is_virtual(vif) &&
3058 1 : (!(vif->vif_flags & VIF_FLAG_MIRROR_TX))) {
3059 1 : if (vr_gro_input(pkt, nh)) {
3060 0 : if (stats)
3061 0 : stats->vrf_gros++;
3062 0 : return NH_PROCESSING_COMPLETE;
3063 : }
3064 : }
3065 :
3066 : /*
3067 : * If for some reason, we have GRO flag set and we have not invoked
3068 : * the GRO, we need to unset
3069 : */
3070 14 : vr_pkt_unset_gro(pkt);
3071 :
3072 14 : if (stats)
3073 14 : stats->vrf_l2_encaps++;
3074 :
3075 14 : vif->vif_tx(vif, pkt, fmd);
3076 :
3077 14 : return NH_PROCESSING_COMPLETE;
3078 : }
3079 :
3080 : static int
3081 55 : nh_encap_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
3082 : struct vr_forwarding_md *fmd, void *ret_data)
3083 : {
3084 55 : bool root = false;
3085 :
3086 55 : if (nh->nh_flags & NH_FLAG_ETREE_ROOT)
3087 35 : root = true;
3088 55 : vr_fmd_update_etree_root(fmd,root);
3089 :
3090 55 : if (pkt->vp_if == nh->nh_dev)
3091 55 : return NH_SOURCE_VALID;
3092 :
3093 0 : return NH_SOURCE_INVALID;
3094 : }
3095 :
3096 : static nh_processing_t
3097 0 : nh_encap_l3_mcast(struct vr_packet *pkt, struct vr_nexthop *nh,
3098 : struct vr_forwarding_md *fmd)
3099 : {
3100 : uint8_t *ptr;
3101 0 : unsigned short dreason = VP_DROP_INVALID_IF;
3102 : struct vr_interface *vif;
3103 : struct vr_ip *ip;
3104 : struct vr_eth *eth;
3105 :
3106 0 : vif = nh->nh_dev;
3107 0 : if (!vif)
3108 0 : goto drop;
3109 :
3110 0 : ip = (struct vr_ip *)pkt_network_header(pkt);
3111 0 : if (vr_ip_is_ip4(ip)) {
3112 0 : pkt->vp_type = VP_TYPE_IP;
3113 0 : eth = (struct vr_eth *)pkt_push(pkt, sizeof(struct vr_eth));
3114 0 : if (!eth) {
3115 0 : dreason = VP_DROP_PUSH;
3116 0 : PKT_LOG(dreason, pkt, 0, VR_NEXTHOP_C, __LINE__);
3117 0 : goto drop;
3118 : }
3119 :
3120 0 : VR_MAC_COPY(eth->eth_smac, vif->vif_mac);
3121 0 : eth->eth_proto = htons(VR_ETH_PROTO_IP);
3122 0 : ptr = (uint8_t *)eth->eth_dmac;
3123 0 : *(unsigned int *)(ptr + 2) = ip->ip_daddr;
3124 :
3125 0 : ptr[0] = 1;
3126 0 : ptr[1] = 0;
3127 0 : ptr[2] = 0x5E;
3128 0 : ptr[3] = 0x07F & ptr[3];
3129 :
3130 :
3131 0 : vif->vif_tx(vif, pkt, fmd);
3132 :
3133 : } else {
3134 0 : dreason = VP_DROP_INVALID_PROTOCOL;
3135 0 : PKT_LOG(dreason, pkt, 0, VR_NEXTHOP_C, __LINE__);
3136 0 : goto drop;
3137 : }
3138 :
3139 0 : return NH_PROCESSING_COMPLETE;
3140 :
3141 0 : drop:
3142 0 : vr_pfree(pkt, dreason);
3143 0 : return NH_PROCESSING_COMPLETE;
3144 : }
3145 :
3146 : static nh_processing_t
3147 31 : nh_encap_l3(struct vr_packet *pkt, struct vr_nexthop *nh,
3148 : struct vr_forwarding_md *fmd)
3149 : {
3150 : int rewrite_len;
3151 : unsigned short *proto_p;
3152 :
3153 : struct vr_ip *ip;
3154 : struct vr_interface *vif;
3155 31 : struct vr_vrf_stats *stats = NULL;
3156 31 : struct vr_forwarding_class_qos *qos = NULL;
3157 :
3158 31 : if (vr_inet_vrf_stats)
3159 31 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
3160 :
3161 31 : vif = nh->nh_dev;
3162 31 : if (!vif) {
3163 0 : PKT_LOG(VP_DROP_INVALID_IF, pkt, 0, VR_NEXTHOP_C, __LINE__);
3164 0 : vr_pfree(pkt, VP_DROP_INVALID_IF);
3165 0 : return NH_PROCESSING_COMPLETE;
3166 : }
3167 :
3168 31 : if (vif_is_fabric(vif)) {
3169 1 : if (!(pkt->vp_flags & VP_FLAG_GROED)) {
3170 1 : qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
3171 1 : if (qos) {
3172 0 : pkt->vp_queue = qos->vfcq_queue_id;
3173 0 : pkt->vp_priority = qos->vfcq_dotonep_qos;
3174 : }
3175 : }
3176 : }
3177 :
3178 31 : ip = (struct vr_ip *)pkt_network_header(pkt);
3179 31 : if (vr_ip_is_ip6(ip)) {
3180 2 : pkt->vp_type = VP_TYPE_IP6;
3181 2 : if (qos)
3182 0 : vr_inet6_set_tos((struct vr_ip6 *)ip, qos->vfcq_dscp);
3183 29 : } else if (vr_ip_is_ip4(ip)) {
3184 28 : pkt->vp_type = VP_TYPE_IP;
3185 28 : if (qos)
3186 0 : vr_inet_set_tos(ip, VR_IP_DSCP(qos->vfcq_dscp));
3187 : } else {
3188 1 : PKT_LOG(VP_DROP_INVALID_PROTOCOL, pkt, 0, VR_NEXTHOP_C, __LINE__);
3189 1 : vr_pfree(pkt, VP_DROP_INVALID_PROTOCOL);
3190 1 : return NH_PROCESSING_COMPLETE;
3191 : }
3192 :
3193 30 : if (vr_pkt_is_diag(pkt)) {
3194 0 : vr_pkt_unset_gro(pkt);
3195 0 : if (stats)
3196 0 : stats->vrf_diags++;
3197 : }
3198 :
3199 30 : if (vr_pkt_is_gro(pkt) && vif_is_virtual(vif) &&
3200 3 : (!(vif->vif_flags & VIF_FLAG_MIRROR_TX))) {
3201 3 : if (vr_gro_input(pkt, nh)) {
3202 0 : if (stats) {
3203 0 : stats->vrf_gros++;
3204 : }
3205 0 : return NH_PROCESSING_COMPLETE;
3206 : }
3207 : }
3208 :
3209 : /*
3210 : * If for some reason, we have GRO flag set and we have not invoked
3211 : * the GRO, we need to unset
3212 : */
3213 30 : vr_pkt_unset_gro(pkt);
3214 :
3215 30 : rewrite_len = vif->vif_set_rewrite(vif, &pkt, fmd, nh->nh_data, nh->nh_encap_len);
3216 30 : if (rewrite_len < 0) {
3217 0 : PKT_LOG(VP_DROP_REWRITE_FAIL, pkt, 0, VR_NEXTHOP_C, __LINE__);
3218 0 : vr_pfree(pkt, VP_DROP_REWRITE_FAIL);
3219 0 : return NH_PROCESSING_COMPLETE;
3220 : }
3221 :
3222 30 : if (rewrite_len) {
3223 29 : proto_p = (unsigned short *)(pkt_data(pkt) + nh->nh_encap_len - 2);
3224 29 : if (pkt->vp_type == VP_TYPE_IP6)
3225 2 : *proto_p = htons(VR_ETH_PROTO_IP6);
3226 : else
3227 27 : *proto_p = htons(VR_ETH_PROTO_IP);
3228 : }
3229 :
3230 : /*
3231 : * Look if this is the Diag packet to trap to agent
3232 : */
3233 30 : if (vr_pkt_is_diag(pkt)) {
3234 0 : pkt->vp_if = vif;
3235 0 : vr_pset_data(pkt, pkt->vp_data);
3236 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_DIAG, &vif->vif_idx);
3237 0 : return NH_PROCESSING_COMPLETE;
3238 : }
3239 :
3240 30 : if (stats) {
3241 30 : stats->vrf_encaps++;
3242 : }
3243 :
3244 30 : vif->vif_tx(vif, pkt, fmd);
3245 :
3246 30 : return NH_PROCESSING_COMPLETE;
3247 : }
3248 :
3249 : static int
3250 267 : vr_nexthop_delete(vr_nexthop_req *req)
3251 : {
3252 : struct vr_nexthop *nh;
3253 267 : int ret = 0;
3254 :
3255 267 : nh = vrouter_get_nexthop(req->nhr_rid, req->nhr_id);
3256 267 : if (!nh) {
3257 4 : ret = -EINVAL;
3258 : } else {
3259 263 : vr_offload_nexthop_del(nh);
3260 263 : vrouter_put_nexthop(nh);
3261 263 : nh->nh_destructor(nh);
3262 : }
3263 :
3264 267 : ret = vr_send_response(ret);
3265 :
3266 267 : return ret;
3267 : }
3268 :
3269 : static int
3270 0 : nh_resolve_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3271 : {
3272 0 : nh->nh_reach_nh = nh_resolve;
3273 0 : return 0;
3274 : }
3275 :
3276 : static int
3277 16 : nh_l2_rcv_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3278 : {
3279 16 : nh->nh_reach_nh = nh_l2_rcv;
3280 16 : return 0;
3281 : }
3282 :
3283 : static int
3284 23 : nh_rcv_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3285 : {
3286 23 : int ret = 0;
3287 : struct vr_interface *vif, *old_vif;
3288 :
3289 23 : old_vif = nh->nh_dev;
3290 :
3291 23 : vif = vrouter_get_interface(nh->nh_rid, req->nhr_encap_oif_id[0]);
3292 23 : if (!vif) {
3293 0 : ret = -ENODEV;
3294 0 : goto exit_add;
3295 : }
3296 :
3297 : /*
3298 : * We need to delete the reference to old_vif only after new vif is
3299 : * added to NH
3300 : */
3301 23 : nh->nh_dev = vif;
3302 23 : if (old_vif)
3303 0 : vrouter_put_interface(old_vif);
3304 :
3305 23 : exit_add:
3306 23 : if (nh->nh_dev) {
3307 23 : nh->nh_reach_nh = nh_l3_rcv;
3308 : }
3309 :
3310 23 : return ret;
3311 : }
3312 :
3313 : static int
3314 1 : nh_vrf_translate_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3315 : {
3316 1 : nh->nh_reach_nh = nh_vrf_translate;
3317 1 : return 0;
3318 : }
3319 :
3320 : static int
3321 5 : nh_composite_mcast_validate(struct vr_component_nh *component_nh,
3322 : vr_nexthop_req *req)
3323 : {
3324 : unsigned int i;
3325 5 : bool l2_seen = false, l3_seen = false;
3326 : struct vr_nexthop *tmp_nh;
3327 :
3328 5 : if (req->nhr_family == AF_INET)
3329 4 : l3_seen = true;
3330 1 : else if (req->nhr_family == AF_BRIDGE)
3331 1 : l2_seen = true;
3332 :
3333 : /* Fabric and EVPN nexthop*/
3334 5 : if (req->nhr_flags & (NH_FLAG_COMPOSITE_FABRIC |
3335 : NH_FLAG_COMPOSITE_EVPN | NH_FLAG_COMPOSITE_TOR)) {
3336 :
3337 1 : if (!l3_seen && !l2_seen)
3338 0 : return -1;
3339 :
3340 2 : for (i = 0; i < req->nhr_nh_list_size; i++) {
3341 1 : tmp_nh = component_nh[i].cnh;
3342 1 : if (!tmp_nh)
3343 0 : continue;
3344 1 : if (tmp_nh->nh_type != NH_TUNNEL)
3345 0 : return -1;
3346 1 : if (tmp_nh->nh_flags & NH_FLAG_TUNNEL_UDP)
3347 0 : return -1;
3348 :
3349 : /* Tor nexthop can only have Vxlan encap tunnels */
3350 1 : if (req->nhr_flags & NH_FLAG_COMPOSITE_TOR) {
3351 0 : if ((tmp_nh->nh_flags & NH_FLAG_TUNNEL_VXLAN) == 0)
3352 0 : return -1;
3353 : }
3354 : }
3355 : }
3356 :
3357 : /* Composite Encap */
3358 5 : if (req->nhr_flags & NH_FLAG_COMPOSITE_ENCAP) {
3359 :
3360 0 : for (i = 0; i < req->nhr_nh_list_size; i++) {
3361 0 : tmp_nh = component_nh[i].cnh;
3362 0 : if (!tmp_nh)
3363 0 : continue;
3364 :
3365 0 : if (tmp_nh->nh_type != NH_ENCAP)
3366 0 : return -1;
3367 :
3368 0 : if (tmp_nh->nh_family == AF_INET) {
3369 0 : if (l2_seen)
3370 0 : return -1;
3371 :
3372 0 : if (!(tmp_nh->nh_flags & NH_FLAG_MCAST))
3373 0 : return -1;
3374 0 : } else if (tmp_nh->nh_family == AF_BRIDGE) {
3375 0 : if (l3_seen)
3376 0 : return -1;
3377 :
3378 0 : if (tmp_nh->nh_flags & NH_FLAG_MCAST)
3379 0 : return -1;
3380 : } else {
3381 0 : return -1;
3382 : }
3383 : }
3384 : }
3385 :
3386 : /* L2 and L3 multicast */
3387 5 : if (req->nhr_flags & NH_FLAG_MCAST) {
3388 :
3389 0 : if (!l3_seen && !l2_seen)
3390 0 : return -1;
3391 :
3392 0 : for (i = 0; i < req->nhr_nh_list_size; i++) {
3393 0 : tmp_nh = component_nh[i].cnh;
3394 : /* NULL component NH is valid */
3395 0 : if (!tmp_nh)
3396 0 : continue;
3397 :
3398 : /* IT can contain only Fabric and L2ENCAP composite */
3399 0 : if (tmp_nh->nh_type != NH_COMPOSITE)
3400 0 : return -1;
3401 :
3402 0 : if (!(tmp_nh->nh_flags &
3403 : (NH_FLAG_COMPOSITE_FABRIC | NH_FLAG_COMPOSITE_EVPN |
3404 : NH_FLAG_COMPOSITE_TOR | NH_FLAG_COMPOSITE_ENCAP))) {
3405 0 : return -1;
3406 : }
3407 :
3408 : }
3409 : }
3410 :
3411 5 : return 0;
3412 : }
3413 :
3414 : static int
3415 5 : nh_composite_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3416 : {
3417 5 : int ret = 0;
3418 5 : unsigned int i, j = 0, active = 0;
3419 : struct vr_nexthop *tmp_nh;
3420 5 : struct vr_component_nh *component_nh = NULL, *component_ecmp = NULL;
3421 :
3422 5 : if (req->nhr_nh_list_size != req->nhr_label_list_size) {
3423 0 : ret = -EINVAL;
3424 0 : goto exit_add;
3425 : }
3426 :
3427 5 : if (req->nhr_nh_list_size) {
3428 5 : component_nh = vr_zalloc(req->nhr_nh_list_size *
3429 : sizeof(struct vr_component_nh), VR_NEXTHOP_COMPONENT_OBJECT);
3430 5 : if (!component_nh) {
3431 0 : ret = -ENOMEM;
3432 0 : goto exit_add;
3433 : }
3434 :
3435 14 : for (i = 0; i < req->nhr_nh_list_size; i++) {
3436 18 : component_nh[i].cnh = vrouter_get_nexthop(req->nhr_rid,
3437 9 : req->nhr_nh_list[i]);
3438 9 : component_nh[i].cnh_label = req->nhr_label_list[i];
3439 9 : if (component_nh[i].cnh)
3440 9 : active++;
3441 :
3442 9 : if (req->nhr_flags & NH_FLAG_COMPOSITE_ECMP) {
3443 8 : component_nh[i].cnh_ecmp_index = i;
3444 : } else {
3445 1 : component_nh[i].cnh_ecmp_index = -1;
3446 : }
3447 : }
3448 :
3449 5 : if (nh_composite_mcast_validate(component_nh, req)) {
3450 0 : ret = -EINVAL;
3451 0 : goto exit_add;
3452 : }
3453 :
3454 5 : if (req->nhr_flags & NH_FLAG_COMPOSITE_ECMP) {
3455 4 : if (active) {
3456 : component_ecmp =
3457 4 : vr_zalloc(active * sizeof(struct vr_component_nh),
3458 : VR_NEXTHOP_COMPONENT_OBJECT);
3459 4 : if (!component_ecmp) {
3460 0 : ret = -ENOMEM;
3461 0 : goto exit_add;
3462 : }
3463 : }
3464 :
3465 12 : for (i = 0; i < req->nhr_nh_list_size; i++) {
3466 8 : if (component_nh[i].cnh) {
3467 8 : memcpy(&component_ecmp[j++], &component_nh[i],
3468 : sizeof(struct vr_component_nh));
3469 : /* this happens implicitly */
3470 : /* nh->nh_component_ecmp[j++].cnh_ecmp_index = i */
3471 : }
3472 : }
3473 : }
3474 : }
3475 :
3476 5 : nh->nh_validate_src = NULL;
3477 : /* Delete the old nexthops first */
3478 5 : if (nh->nh_component_cnt && nh->nh_component_nh) {
3479 0 : for (i = 0; i < nh->nh_component_cnt; i++) {
3480 0 : if (nh->nh_component_nh[i].cnh)
3481 0 : vrouter_put_nexthop(nh->nh_component_nh[i].cnh);
3482 : }
3483 0 : vr_free(nh->nh_component_nh, VR_NEXTHOP_COMPONENT_OBJECT);
3484 0 : nh->nh_component_nh = NULL;
3485 0 : nh->nh_component_cnt = 0;
3486 :
3487 0 : if (nh->nh_component_ecmp) {
3488 0 : vr_free(nh->nh_component_ecmp, VR_NEXTHOP_COMPONENT_OBJECT);
3489 0 : nh->nh_component_ecmp = NULL;
3490 0 : nh->nh_component_ecmp_cnt = 0;
3491 : }
3492 : }
3493 :
3494 : /* Nh list of size 0 is valid */
3495 5 : if (req->nhr_nh_list_size == 0)
3496 0 : goto exit_add;
3497 :
3498 5 : nh->nh_component_nh = component_nh;
3499 5 : if (component_ecmp) {
3500 4 : nh->nh_component_ecmp = component_ecmp;
3501 : }
3502 5 : nh->nh_component_cnt = req->nhr_nh_list_size;
3503 :
3504 5 : exit_add:
3505 : /* This needs to be the last */
3506 5 : if (req->nhr_flags & NH_FLAG_MCAST) {
3507 0 : nh->nh_reach_nh = nh_composite_mcast;
3508 0 : nh->nh_validate_src = nh_composite_mcast_validate_src;
3509 5 : } else if (req->nhr_flags & NH_FLAG_COMPOSITE_ECMP) {
3510 4 : nh->nh_reach_nh = nh_composite_ecmp;
3511 4 : nh->nh_validate_src = nh_composite_ecmp_validate_src;
3512 4 : if (!ret) {
3513 4 : nh_ecmp_store_ecmp_config_hash(req, nh);
3514 4 : nh->nh_component_ecmp_cnt = j;
3515 : }
3516 1 : } else if (req->nhr_flags & NH_FLAG_COMPOSITE_FABRIC) {
3517 1 : nh->nh_reach_nh = nh_composite_fabric;
3518 0 : } else if (req->nhr_flags & NH_FLAG_COMPOSITE_EVPN) {
3519 0 : nh->nh_reach_nh = nh_composite_evpn;
3520 0 : } else if (req->nhr_flags & NH_FLAG_COMPOSITE_ENCAP) {
3521 0 : nh->nh_reach_nh = nh_composite_encap;
3522 0 : } else if (req->nhr_flags & NH_FLAG_COMPOSITE_TOR) {
3523 0 : nh->nh_reach_nh = nh_composite_tor;
3524 : }
3525 :
3526 5 : if (ret) {
3527 0 : if (component_nh) {
3528 0 : for (i = 0; i < req->nhr_nh_list_size; i++) {
3529 0 : tmp_nh = component_nh[i].cnh;
3530 0 : if (tmp_nh)
3531 0 : vrouter_put_nexthop(tmp_nh);
3532 : }
3533 :
3534 0 : vr_free(component_nh, VR_NEXTHOP_COMPONENT_OBJECT);
3535 : }
3536 :
3537 0 : if (component_ecmp) {
3538 0 : vr_free(component_ecmp, VR_NEXTHOP_COMPONENT_OBJECT);
3539 : }
3540 : }
3541 :
3542 5 : return ret;
3543 : }
3544 :
3545 : static inline void
3546 54 : nh_tunnel_set_reach_nh(struct vr_nexthop *nh)
3547 : {
3548 54 : bool dev = false;
3549 : int i;
3550 :
3551 54 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
3552 36 : for (i = 0; i < VR_MAX_PHY_INF; i++)
3553 27 : if (nh->nh_encap_valid[i])
3554 15 : dev = true;
3555 : } else {
3556 45 : if (nh->nh_dev)
3557 44 : dev = true;
3558 : }
3559 :
3560 54 : if (nh->nh_flags & NH_FLAG_TUNNEL_GRE) {
3561 6 : if (dev) {
3562 6 : nh->nh_reach_nh = nh_gre_tunnel;
3563 : }
3564 48 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP) {
3565 1 : nh->nh_reach_nh = nh_udp_tunnel;
3566 47 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS) {
3567 40 : if (dev) {
3568 39 : nh->nh_reach_nh = nh_mpls_udp_tunnel;
3569 : }
3570 7 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_VXLAN) {
3571 7 : if (dev) {
3572 7 : nh->nh_reach_nh = nh_vxlan_tunnel;
3573 : }
3574 0 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
3575 0 : nh->nh_reach_nh = nh_pbb_tunnel;
3576 : }
3577 :
3578 54 : return;
3579 : }
3580 :
3581 : static int
3582 54 : nh_tunnel_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3583 : {
3584 54 : int i, ret = 0;
3585 54 : struct vr_interface *vif[VR_MAX_PHY_INF] = {NULL};
3586 54 : struct vr_interface *old_vif[VR_MAX_PHY_INF] = {NULL};
3587 54 : struct vr_interface *crypt_vif = NULL, *old_crypt_vif = NULL;
3588 :
3589 54 : if (req->nhr_family == AF_INET6) {
3590 0 : if (!req->nhr_tun_sip6 || !req->nhr_tun_dip6) {
3591 0 : ret = -EINVAL;
3592 0 : goto exit_add;
3593 : }
3594 54 : } else if (req->nhr_family == AF_INET) {
3595 54 : if (!req->nhr_tun_sip || !req->nhr_tun_dip) {
3596 0 : ret = -EINVAL;
3597 0 : goto exit_add;
3598 : }
3599 : }
3600 :
3601 216 : for (i = 0; i < VR_MAX_PHY_INF; i++)
3602 162 : old_vif[i] = nh->nh_dev_arr[i];
3603 :
3604 : /* Reset the nh valid underlay vif count on every add or update*/
3605 54 : nh->nh_valid_underlay_dev_count = 0;
3606 :
3607 54 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
3608 36 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
3609 27 : nh->nh_valid_underlay_dev[i] = NULL;
3610 27 : nh->nh_encap_valid[i] = req->nhr_encap_valid[i];
3611 27 : if (nh->nh_encap_valid[i]) {
3612 30 : vif[i] = vrouter_get_interface(nh->nh_rid,
3613 15 : req->nhr_encap_oif_id[i]);
3614 15 : nh->nh_valid_underlay_dev[nh->nh_valid_underlay_dev_count]
3615 15 : = vif[i];
3616 15 : nh->nh_valid_underlay_dev_count += 1;
3617 : } else
3618 12 : vif[i] = NULL;
3619 : }
3620 : } else {
3621 45 : vif[0] = vrouter_get_interface(nh->nh_rid, req->nhr_encap_oif_id[0]);
3622 : }
3623 :
3624 54 : old_crypt_vif = nh->nh_crypt_dev;
3625 54 : crypt_vif = vrouter_get_interface(nh->nh_rid, req->nhr_encap_crypt_oif_id);
3626 54 : nh->nh_crypt_dev = crypt_vif;
3627 54 : if (old_crypt_vif) {
3628 2 : vrouter_put_interface(old_crypt_vif);
3629 : }
3630 :
3631 54 : if (nh->nh_flags & NH_FLAG_TUNNEL_GRE) {
3632 6 : if (!(vif[0] || vif[1] || vif[2])) {
3633 0 : ret = -ENODEV;
3634 0 : goto exit_add;
3635 : }
3636 :
3637 6 : nh->nh_gre_tun_sip = req->nhr_tun_sip;
3638 6 : nh->nh_gre_tun_dip = req->nhr_tun_dip;
3639 6 : nh->nh_validate_src = nh_gre_tunnel_validate_src;
3640 6 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
3641 2 : nh->nh_gre_tun_encap_len = req->nhr_encap_len;
3642 8 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
3643 6 : if (nh->nh_encap_valid[i])
3644 6 : nh->nh_dev_arr[i] = vif[i];
3645 : else
3646 0 : nh->nh_dev_arr[i] = NULL;
3647 : }
3648 : } else {
3649 4 : nh->nh_gre_tun_encap_len = req->nhr_encap_size;
3650 4 : nh->nh_dev = vif[0];
3651 : }
3652 :
3653 6 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
3654 0 : nh->nh_gre_tun_label = req->nhr_transport_label;
3655 : }
3656 48 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP) {
3657 1 : if (req->nhr_family == AF_INET) {
3658 1 : nh->nh_udp_tun_sip = req->nhr_tun_sip;
3659 1 : nh->nh_udp_tun_dip = req->nhr_tun_dip;
3660 1 : nh->nh_udp_tun_sport = req->nhr_tun_sport;
3661 1 : nh->nh_udp_tun_dport = req->nhr_tun_dport;
3662 1 : nh->nh_udp_tun_encap_len = req->nhr_encap_size;
3663 0 : } else if (req->nhr_family == AF_INET6) {
3664 0 : if (!nh->nh_udp_tun6_sip) {
3665 0 : nh->nh_udp_tun6_sip = vr_malloc(VR_IP6_ADDRESS_LEN,
3666 : VR_NETWORK_ADDRESS_OBJECT);
3667 0 : if (!nh->nh_udp_tun6_sip) {
3668 0 : ret = -ENOMEM;
3669 0 : goto exit_error;
3670 : }
3671 : }
3672 0 : memcpy(nh->nh_udp_tun6_sip, req->nhr_tun_sip6, VR_IP6_ADDRESS_LEN);
3673 :
3674 0 : if (!nh->nh_udp_tun6_dip) {
3675 0 : nh->nh_udp_tun6_dip = vr_malloc(VR_IP6_ADDRESS_LEN,
3676 : VR_NETWORK_ADDRESS_OBJECT);
3677 0 : if (!nh->nh_udp_tun6_dip) {
3678 0 : ret = -ENOMEM;
3679 0 : goto exit_error;
3680 : }
3681 : }
3682 0 : memcpy(nh->nh_udp_tun6_dip, req->nhr_tun_dip6,
3683 : VR_IP6_ADDRESS_LEN);
3684 0 : nh->nh_udp_tun6_sport = req->nhr_tun_sport;
3685 0 : nh->nh_udp_tun6_dport = req->nhr_tun_dport;
3686 0 : nh->nh_udp_tun6_encap_len = req->nhr_encap_size;
3687 : } else {
3688 0 : ret = -EINVAL;
3689 0 : goto exit_error;
3690 : }
3691 : /* VIFs should be null, but lets clean if one is found */
3692 4 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
3693 3 : if (vif[i])
3694 1 : vrouter_put_interface(vif[i]);
3695 : }
3696 47 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS) {
3697 40 : if (!(vif[0] || vif[1] || vif[2])) {
3698 1 : ret = -ENODEV;
3699 1 : goto exit_add;
3700 : }
3701 :
3702 39 : nh->nh_udp_tun_sip = req->nhr_tun_sip;
3703 39 : nh->nh_udp_tun_dip = req->nhr_tun_dip;
3704 39 : nh->nh_validate_src = nh_mpls_udp_tunnel_validate_src;
3705 39 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
3706 5 : nh->nh_udp_tun_encap_len = req->nhr_encap_len;
3707 20 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
3708 15 : if (nh->nh_encap_valid[i])
3709 7 : nh->nh_dev_arr[i] = vif[i];
3710 : else
3711 8 : nh->nh_dev_arr[i] = NULL;
3712 : }
3713 : } else {
3714 34 : nh->nh_udp_tun_encap_len = req->nhr_encap_size;
3715 34 : nh->nh_dev = vif[0];
3716 : }
3717 :
3718 39 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
3719 0 : nh->nh_udp_tun_label = req->nhr_transport_label;
3720 : }
3721 7 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_VXLAN) {
3722 7 : if (!(vif[0] || vif[1] || vif[2])) {
3723 0 : ret = -ENODEV;
3724 0 : goto exit_add;
3725 : }
3726 :
3727 7 : nh->nh_vxlan_tun_sip = req->nhr_tun_sip;
3728 7 : nh->nh_vxlan_tun_dip = req->nhr_tun_dip;
3729 7 : nh->nh_validate_src = nh_vxlan_tunnel_validate_src;
3730 7 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
3731 1 : nh->nh_vxlan_tun_encap_len = req->nhr_encap_len;
3732 4 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
3733 3 : if (nh->nh_encap_valid[i])
3734 2 : nh->nh_dev_arr[i] = vif[i];
3735 : else
3736 1 : nh->nh_dev_arr[i] = NULL;
3737 : }
3738 : } else {
3739 6 : nh->nh_udp_tun_encap_len = req->nhr_encap_size;
3740 6 : nh->nh_dev = vif[0];
3741 : }
3742 :
3743 7 : if (nh->nh_flags & NH_FLAG_L3_VXLAN) {
3744 0 : if ((req->nhr_rw_dst_mac_size != VR_ETHER_ALEN) ||
3745 0 : (IS_MAC_ZERO(req->nhr_rw_dst_mac))) {
3746 0 : ret = -EINVAL;
3747 0 : goto exit_add;
3748 : }
3749 0 : VR_MAC_COPY(nh->nh_vxlan_tun_l3_mac, req->nhr_rw_dst_mac);
3750 : }
3751 0 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
3752 0 : if (!(nh->nh_flags & NH_FLAG_INDIRECT)) {
3753 0 : ret = -EINVAL;
3754 0 : goto exit_add;
3755 : }
3756 :
3757 0 : if ((req->nhr_pbb_mac_size != VR_ETHER_ALEN) ||
3758 0 : (IS_MAC_ZERO(req->nhr_pbb_mac))) {
3759 0 : ret = -EINVAL;
3760 0 : goto exit_add;
3761 : }
3762 :
3763 0 : nh->nh_pbb_label = -1;
3764 0 : if (req->nhr_label_list_size)
3765 0 : nh->nh_pbb_label = req->nhr_label_list[0];
3766 :
3767 0 : VR_MAC_COPY(nh->nh_pbb_mac, req->nhr_pbb_mac);
3768 0 : nh->nh_validate_src = nh_pbb_tunnel_validate_src;
3769 0 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
3770 0 : if (vif[i])
3771 0 : vrouter_put_interface(vif[i]);
3772 : }
3773 : } else {
3774 : /* Reference to VIf should be cleaned */
3775 0 : for (i = 0; i < VR_MAX_PHY_INF; i++)
3776 0 : if (vif[i])
3777 0 : vrouter_put_interface(vif[i]);
3778 0 : if (crypt_vif)
3779 0 : vrouter_put_interface(crypt_vif);
3780 :
3781 0 : return -EINVAL;
3782 : }
3783 :
3784 53 : memcpy(nh->nh_data, req->nhr_encap, req->nhr_encap_size);
3785 212 : for (i =0; i < VR_MAX_PHY_INF; i++) {
3786 159 : if (old_vif[i])
3787 4 : vrouter_put_interface(old_vif[i]);
3788 : }
3789 :
3790 53 : exit_add:
3791 54 : nh_tunnel_set_reach_nh(nh);
3792 :
3793 54 : exit_error:
3794 54 : return ret;
3795 : }
3796 :
3797 : static int
3798 0 : nh_indirect_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3799 : {
3800 0 : struct vr_nexthop *old_nh, *direct_nh = NULL;
3801 :
3802 : /*
3803 : * Following check needs to be enahnced every time we make a new
3804 : * indirect nexthop
3805 : */
3806 0 : if ((nh->nh_type != NH_TUNNEL) ||
3807 0 : (!(nh->nh_flags & NH_FLAG_TUNNEL_PBB)))
3808 0 : return -EINVAL;
3809 :
3810 : /*
3811 : * Lets allow without direct nh for greater convenience of adds,
3812 : * changes, but only one direct nh
3813 : */
3814 0 : if ((unsigned int)req->nhr_nh_list_size > 1)
3815 0 : return -EINVAL;
3816 :
3817 0 : if (req->nhr_nh_list_size) {
3818 0 : direct_nh = vrouter_get_nexthop(req->nhr_rid, req->nhr_nh_list[0]);
3819 0 : if (!direct_nh)
3820 0 : return -EINVAL;
3821 : }
3822 :
3823 : /* Remove the old nh */
3824 0 : old_nh = nh->nh_direct_nh;
3825 0 : nh->nh_direct_nh = direct_nh;
3826 0 : if (old_nh)
3827 0 : vrouter_put_nexthop(old_nh);
3828 :
3829 0 : return 0;
3830 : }
3831 :
3832 : static int
3833 178 : nh_encap_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3834 : {
3835 178 : int ret = 0;
3836 : struct vr_interface *vif, *old_vif;
3837 :
3838 178 : old_vif = nh->nh_dev;
3839 :
3840 178 : if ((req->nhr_family != AF_INET) && (req->nhr_family != AF_BRIDGE)) {
3841 0 : ret = -EINVAL;
3842 0 : goto exit_add;
3843 : }
3844 :
3845 178 : if ((req->nhr_family == AF_BRIDGE) && (req->nhr_flags & NH_FLAG_MCAST)) {
3846 0 : ret = -EINVAL;
3847 0 : goto exit_add;
3848 : }
3849 :
3850 178 : if ((req->nhr_family == AF_INET) && !(req->nhr_flags & NH_FLAG_MCAST)) {
3851 145 : if (req->nhr_encap_size < VR_ETHER_ALEN) {
3852 0 : ret = -EINVAL;
3853 0 : goto exit_add;
3854 : }
3855 : }
3856 :
3857 178 : vif = vrouter_get_interface(nh->nh_rid, req->nhr_encap_oif_id[0]);
3858 178 : if (!vif) {
3859 0 : ret = -EINVAL;
3860 0 : goto exit_add;
3861 : }
3862 :
3863 178 : nh->nh_encap_family = req->nhr_encap_family;
3864 178 : nh->nh_encap_len = req->nhr_encap_size;
3865 178 : if (nh->nh_encap_len) {
3866 177 : memcpy(nh->nh_data, req->nhr_encap, nh->nh_encap_len);
3867 : }
3868 :
3869 178 : nh->nh_dev = vif;
3870 178 : if (old_vif)
3871 10 : vrouter_put_interface(old_vif);
3872 :
3873 168 : exit_add:
3874 178 : if (nh->nh_dev) {
3875 178 : nh->nh_validate_src = nh_encap_validate_src;
3876 178 : if (req->nhr_family == AF_BRIDGE) {
3877 33 : nh->nh_reach_nh = nh_encap_l2;
3878 145 : } else if (nh->nh_flags & NH_FLAG_MCAST) {
3879 0 : nh->nh_reach_nh = nh_encap_l3_mcast;
3880 : } else {
3881 145 : nh->nh_reach_nh = nh_encap_l3;
3882 : }
3883 : }
3884 :
3885 178 : return ret;
3886 : }
3887 :
3888 : static int
3889 0 : nh_discard_add(struct vr_nexthop *nh, vr_nexthop_req *req)
3890 : {
3891 0 : nh->nh_family = req->nhr_family;
3892 0 : nh->nh_type = NH_DISCARD;
3893 0 : nh->nh_router = vrouter_get(0);
3894 0 : nh->nh_reach_nh = nh_discard;
3895 0 : return 0;
3896 : }
3897 :
3898 : static bool
3899 277 : vr_nexthop_valid_request(vr_nexthop_req *req)
3900 : {
3901 277 : struct vrouter *router = vrouter_get(req->nhr_rid);
3902 :
3903 277 : if (!router)
3904 0 : return false;
3905 :
3906 277 : if ((unsigned int)req->nhr_id >= router->vr_max_nexthops)
3907 0 : return false;
3908 :
3909 277 : if ((unsigned int)req->nhr_type >= NH_MAX)
3910 0 : return false;
3911 :
3912 277 : return true;
3913 : }
3914 :
3915 : static int
3916 265 : vr_nexthop_size(vr_nexthop_req *req)
3917 : {
3918 265 : unsigned int size = sizeof(struct vr_nexthop);
3919 :
3920 265 : if ((req->nhr_type == NH_ENCAP) || (req->nhr_type == NH_TUNNEL))
3921 220 : if (req->nhr_encap)
3922 220 : size += req->nhr_encap_size;
3923 :
3924 265 : return size;
3925 : }
3926 :
3927 : static bool
3928 12 : vr_nexthop_valid_change(vr_nexthop_req *req, struct vr_nexthop *nh)
3929 : {
3930 :
3931 12 : if (!(req->nhr_flags & NH_FLAG_VALID))
3932 0 : return true;
3933 :
3934 12 : if (req->nhr_type != nh->nh_type)
3935 0 : return false;
3936 :
3937 12 : if (req->nhr_encap_size &&
3938 11 : req->nhr_encap_size != nh->nh_data_size)
3939 0 : return false;
3940 :
3941 : /* Indirect to non-indirect and other way is not allowed */
3942 12 : if ((req->nhr_flags & NH_FLAG_INDIRECT) ^
3943 12 : (nh->nh_flags & NH_FLAG_INDIRECT))
3944 0 : return false;
3945 :
3946 12 : return true;
3947 : }
3948 :
3949 :
3950 : int
3951 277 : vr_nexthop_add(vr_nexthop_req *req)
3952 : {
3953 277 : int ret = 0, len = 0;
3954 277 : bool invalid_to_valid = false, change = false;
3955 : struct vr_nexthop *nh;
3956 277 : struct vrouter *router = vrouter_get(req->nhr_rid);
3957 :
3958 277 : if (!vr_nexthop_valid_request(req) && (ret = -EINVAL))
3959 0 : goto generate_resp;
3960 :
3961 277 : nh = __vrouter_get_nexthop(router, req->nhr_id);
3962 277 : if (!nh) {
3963 265 : len = vr_nexthop_size(req);
3964 265 : if (len < 0) {
3965 0 : ret = -EINVAL;
3966 0 : goto generate_resp;
3967 : }
3968 :
3969 265 : nh = vr_zalloc(len, VR_NEXTHOP_OBJECT);
3970 265 : if (!nh) {
3971 0 : ret = -ENOMEM;
3972 0 : goto generate_resp;
3973 : }
3974 :
3975 265 : nh->nh_data_size = len - sizeof(struct vr_nexthop);
3976 : } else {
3977 12 : change = true;
3978 : /*
3979 : * If modification of old_nh change the action to discard and ensure
3980 : * everybody sees that
3981 : */
3982 12 : if (!vr_nexthop_valid_change(req, nh)) {
3983 0 : ret = -EINVAL;
3984 0 : goto generate_resp;
3985 : }
3986 :
3987 : /* Lets track if invalid to valid change */
3988 12 : if ((req->nhr_flags & NH_FLAG_VALID) &&
3989 12 : !(nh->nh_flags & NH_FLAG_VALID))
3990 0 : invalid_to_valid = true;
3991 :
3992 : /* If valid to invalid lets propogate flags immediately */
3993 12 : if (!(req->nhr_flags & NH_FLAG_VALID) &&
3994 0 : (nh->nh_flags & NH_FLAG_VALID))
3995 0 : nh->nh_flags = req->nhr_flags;
3996 :
3997 : /* For a change lets always point to discard */
3998 12 : nh->nh_reach_nh = nh_discard;
3999 12 : vr_delay_op();
4000 : }
4001 :
4002 277 : nh->nh_reach_nh = nh_discard;
4003 277 : nh->nh_destructor = nh_del;
4004 277 : nh->nh_type = req->nhr_type;
4005 277 : nh->nh_family = req->nhr_family;
4006 277 : nh->nh_id = req->nhr_id;
4007 277 : nh->nh_rid = req->nhr_rid;
4008 277 : nh->nh_router = vrouter_get(nh->nh_rid);
4009 277 : nh->nh_vrf = req->nhr_vrf;
4010 277 : nh->nh_direct_nh = NULL;
4011 :
4012 : /*
4013 : * If invalid to valid, lets make it valid after the whole nexthop
4014 : * is cookedup. For invalid to invalid, valid to valid, lets
4015 : * copy the flags as is
4016 : */
4017 277 : if (invalid_to_valid)
4018 0 : nh->nh_flags = (req->nhr_flags & ~NH_FLAG_VALID);
4019 : else
4020 277 : nh->nh_flags = req->nhr_flags;
4021 :
4022 277 : if (req->nhr_flags & NH_FLAG_VALID) {
4023 277 : if (nh->nh_flags & NH_FLAG_INDIRECT) {
4024 0 : ret = nh_indirect_add(nh, req);
4025 0 : if (ret)
4026 0 : goto error;
4027 : }
4028 277 : switch (nh->nh_type) {
4029 178 : case NH_ENCAP:
4030 178 : ret = nh_encap_add(nh, req);
4031 178 : break;
4032 :
4033 54 : case NH_TUNNEL:
4034 54 : ret = nh_tunnel_add(nh, req);
4035 54 : break;
4036 :
4037 23 : case NH_RCV:
4038 23 : ret = nh_rcv_add(nh, req);
4039 23 : break;
4040 :
4041 16 : case NH_L2_RCV:
4042 16 : ret = nh_l2_rcv_add(nh, req);
4043 16 : break;
4044 :
4045 0 : case NH_RESOLVE:
4046 0 : ret = nh_resolve_add(nh, req);
4047 0 : break;
4048 :
4049 0 : case NH_DISCARD:
4050 0 : ret = nh_discard_add(nh, req);
4051 0 : break;
4052 :
4053 5 : case NH_COMPOSITE:
4054 5 : ret = nh_composite_add(nh, req);
4055 5 : break;
4056 :
4057 1 : case NH_VRF_TRANSLATE:
4058 1 : ret = nh_vrf_translate_add(nh, req);
4059 1 : break;
4060 :
4061 0 : default:
4062 0 : ret = -EINVAL;
4063 : }
4064 :
4065 : }
4066 :
4067 0 : error:
4068 277 : if (ret) {
4069 1 : if (!change) {
4070 1 : if (nh->nh_destructor) {
4071 1 : nh->nh_destructor(nh);
4072 : }
4073 : }
4074 :
4075 1 : goto generate_resp;
4076 : }
4077 :
4078 : /* Mark he nexthop valid after whole nexthop is cooked incase of
4079 : * invalid to valid transition
4080 : */
4081 276 : if (invalid_to_valid)
4082 0 : nh->nh_flags |= NH_FLAG_VALID;
4083 :
4084 276 : ret = vrouter_add_nexthop(nh);
4085 :
4086 276 : if (ret) {
4087 0 : nh->nh_destructor(nh);
4088 0 : goto generate_resp;
4089 : }
4090 : else /* notify hw offload of change, if enabled */
4091 276 : ret = vr_offload_nexthop_add(nh);
4092 :
4093 : /* if offload failed, delete kernel entry for consistency */
4094 276 : if (ret)
4095 0 : nh->nh_destructor(nh);
4096 :
4097 276 : generate_resp:
4098 277 : ret = vr_send_response(ret);
4099 :
4100 277 : return ret;
4101 : }
4102 :
4103 : unsigned int
4104 25 : vr_nexthop_req_get_size(void *req_p)
4105 : {
4106 25 : int size = 4 * sizeof(vr_nexthop_req);
4107 25 : vr_nexthop_req *req = (vr_nexthop_req *)req_p;
4108 :
4109 25 : size += req->nhr_encap_size;
4110 :
4111 25 : if (req->nhr_nh_list_size)
4112 0 : size += (4 * req->nhr_nh_list_size);
4113 :
4114 25 : if (req->nhr_label_list_size)
4115 0 : size += (4 * req->nhr_label_list_size);
4116 :
4117 25 : if (req->nhr_encap_oif_id_size)
4118 25 : size += (4 * req->nhr_encap_oif_id_size);
4119 :
4120 25 : if (req->nhr_encap_valid_size)
4121 4 : size += (4 * req->nhr_encap_valid_size);
4122 :
4123 25 : size += req->nhr_pbb_mac_size;
4124 :
4125 25 : if ((req->nhr_type == NH_TUNNEL) &&
4126 5 : (req->nhr_flags & NH_FLAG_TUNNEL_UDP) &&
4127 0 : (req->nhr_family == AF_INET6))
4128 0 : size += (VR_IP6_ADDRESS_LEN * 2 * 4);
4129 :
4130 25 : return size;
4131 : }
4132 :
4133 : /* we expect the caller to bzero req, before sending it here */
4134 : static int
4135 25 : vr_nexthop_make_req(vr_nexthop_req *req, struct vr_nexthop *nh)
4136 : {
4137 : unsigned int i;
4138 25 : unsigned char *encap = NULL;
4139 : struct vr_nexthop *cnh;
4140 :
4141 25 : bool dump = false;
4142 :
4143 25 : if (req->h_op == SANDESH_OP_DUMP)
4144 0 : dump = true;
4145 :
4146 25 : req->nhr_type = nh->nh_type;
4147 25 : req->nhr_family = nh->nh_family;
4148 25 : req->nhr_flags = nh->nh_flags;
4149 25 : req->nhr_id = nh->nh_id;
4150 25 : req->nhr_rid = nh->nh_rid;
4151 25 : req->nhr_ref_cnt = nh->nh_users;
4152 25 : req->nhr_nh_list_size = 0;
4153 25 : req->nhr_vrf = nh->nh_vrf;
4154 :
4155 25 : if ((nh->nh_flags & NH_FLAG_INDIRECT) && (cnh = nh->nh_direct_nh)) {
4156 0 : req->nhr_nh_list_size = 1;
4157 0 : req->nhr_nh_list =
4158 0 : vr_zalloc(req->nhr_nh_list_size * sizeof(unsigned int),
4159 : VR_NEXTHOP_REQ_LIST_OBJECT);
4160 0 : if (!req->nhr_nh_list)
4161 0 : return -ENOMEM;
4162 0 : req->nhr_nh_list[0] = cnh->nh_id;
4163 : }
4164 :
4165 25 : switch (nh->nh_type) {
4166 0 : case NH_RCV:
4167 0 : if (nh->nh_dev)
4168 0 : req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
4169 0 : break;
4170 :
4171 0 : case NH_L2_RCV:
4172 0 : if (nh->nh_dev)
4173 0 : req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
4174 0 : break;
4175 :
4176 12 : case NH_ENCAP:
4177 12 : if (nh->nh_dev)
4178 12 : req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
4179 12 : req->nhr_encap_size = nh->nh_encap_len;
4180 12 : req->nhr_encap_family = nh->nh_encap_family;
4181 12 : if (req->nhr_encap_size)
4182 11 : encap = nh->nh_data;
4183 12 : break;
4184 :
4185 0 : case NH_COMPOSITE:
4186 0 : req->nhr_nh_list_size = req->nhr_nh_count = nh->nh_component_cnt;
4187 0 : if (dump && (req->nhr_nh_list_size > VR_NEXTHOP_COMPONENT_DUMP_LIMIT))
4188 0 : req->nhr_nh_list_size = VR_NEXTHOP_COMPONENT_DUMP_LIMIT;
4189 0 : req->nhr_ecmp_config_hash = nh->nh_ecmp_config_hash &
4190 : NH_ECMP_CONFIG_HASH_MASK;
4191 :
4192 0 : if (nh->nh_component_cnt) {
4193 0 : req->nhr_nh_list =
4194 0 : vr_zalloc(req->nhr_nh_list_size * sizeof(unsigned int),
4195 : VR_NEXTHOP_REQ_LIST_OBJECT);
4196 0 : if (!req->nhr_nh_list)
4197 0 : return -ENOMEM;
4198 :
4199 0 : req->nhr_label_list_size = req->nhr_nh_list_size;
4200 0 : req->nhr_label_list =
4201 0 : vr_zalloc(req->nhr_label_list_size * sizeof(unsigned int),
4202 : VR_NEXTHOP_REQ_LIST_OBJECT);
4203 : /* don't bother about freeing. we will free it in req_destroy */
4204 0 : if (!req->nhr_label_list)
4205 0 : return -ENOMEM;
4206 :
4207 0 : for (i = 0; i < req->nhr_nh_list_size; i++) {
4208 0 : if (nh->nh_component_nh[i].cnh)
4209 0 : req->nhr_nh_list[i] = nh->nh_component_nh[i].cnh->nh_id;
4210 : else
4211 0 : req->nhr_nh_list[i] = -1;
4212 :
4213 0 : req->nhr_label_list[i] = nh->nh_component_nh[i].cnh_label;
4214 : }
4215 : }
4216 :
4217 0 : break;
4218 :
4219 5 : case NH_TUNNEL:
4220 5 : if (nh->nh_crypt_dev)
4221 4 : req->nhr_encap_crypt_oif_id = nh->nh_crypt_dev->vif_idx;
4222 5 : req->nhr_encap_family = nh->nh_encap_family;
4223 5 : if (nh->nh_flags & NH_FLAG_TUNNEL_GRE) {
4224 0 : req->nhr_tun_sip = nh->nh_gre_tun_sip;
4225 0 : req->nhr_tun_dip = nh->nh_gre_tun_dip;
4226 0 : req->nhr_encap_size = nh->nh_data_size;
4227 0 : if (req->nhr_encap_size)
4228 0 : encap = nh->nh_data;
4229 0 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
4230 0 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
4231 0 : req->nhr_encap_valid[i] = nh->nh_encap_valid[i];
4232 0 : if (nh->nh_encap_valid[i])
4233 0 : req->nhr_encap_oif_id[i] = nh->nh_dev_arr[i]->vif_idx;
4234 : else
4235 0 : req->nhr_encap_oif_id[i] = -1;
4236 : }
4237 : }
4238 : else {
4239 0 : if (nh->nh_dev) {
4240 0 : req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
4241 : }
4242 : }
4243 0 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
4244 0 : req->nhr_transport_label = nh->nh_gre_tun_label;
4245 : }
4246 5 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP) {
4247 0 : if (nh->nh_family == AF_INET) {
4248 0 : req->nhr_tun_sip = nh->nh_udp_tun_sip;
4249 0 : req->nhr_tun_dip = nh->nh_udp_tun_dip;
4250 0 : req->nhr_encap_size = nh->nh_udp_tun_encap_len;
4251 0 : req->nhr_tun_sport = nh->nh_udp_tun_sport;
4252 0 : req->nhr_tun_dport = nh->nh_udp_tun_dport;
4253 0 : } else if (nh->nh_family == AF_INET6) {
4254 0 : if (req->nhr_tun_sip6_size && req->nhr_tun_sip6)
4255 0 : memcpy(req->nhr_tun_sip6, nh->nh_udp_tun6_sip,
4256 : VR_IP6_ADDRESS_LEN);
4257 0 : if (req->nhr_tun_dip6_size && req->nhr_tun_dip6)
4258 0 : memcpy(req->nhr_tun_dip6, nh->nh_udp_tun6_dip,
4259 : VR_IP6_ADDRESS_LEN);
4260 0 : req->nhr_encap_size = nh->nh_udp_tun6_encap_len;
4261 0 : req->nhr_tun_sport = nh->nh_udp_tun6_sport;
4262 0 : req->nhr_tun_dport = nh->nh_udp_tun6_dport;
4263 : }
4264 :
4265 0 : if (req->nhr_encap_size)
4266 0 : encap = nh->nh_data;
4267 0 : if (nh->nh_dev) {
4268 0 : req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
4269 : }
4270 5 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS) {
4271 4 : req->nhr_tun_sip = nh->nh_udp_tun_sip;
4272 4 : req->nhr_tun_dip = nh->nh_udp_tun_dip;
4273 4 : req->nhr_encap_size = nh->nh_data_size;
4274 4 : if (req->nhr_encap_size)
4275 4 : encap = nh->nh_data;
4276 4 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
4277 16 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
4278 12 : req->nhr_encap_valid[i] = nh->nh_encap_valid[i];
4279 12 : if (nh->nh_encap_valid[i])
4280 6 : req->nhr_encap_oif_id[i] = nh->nh_dev_arr[i]->vif_idx;
4281 : else
4282 6 : req->nhr_encap_oif_id[i] = -1;
4283 : }
4284 : }
4285 : else {
4286 0 : if (nh->nh_dev) {
4287 0 : req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
4288 : }
4289 : }
4290 4 : if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
4291 0 : req->nhr_transport_label = nh->nh_udp_tun_label;
4292 : }
4293 1 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_VXLAN) {
4294 1 : req->nhr_tun_sip = nh->nh_vxlan_tun_sip;
4295 1 : req->nhr_tun_dip = nh->nh_vxlan_tun_dip;
4296 1 : req->nhr_encap_size = nh->nh_data_size;
4297 1 : if (req->nhr_encap_size)
4298 1 : encap = nh->nh_data;
4299 1 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
4300 0 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
4301 0 : req->nhr_encap_valid[i] = nh->nh_encap_valid[i];
4302 0 : if (nh->nh_encap_valid[i])
4303 0 : req->nhr_encap_oif_id[i] = nh->nh_dev_arr[i]->vif_idx;
4304 : else
4305 0 : req->nhr_encap_oif_id[i] = -1;
4306 : }
4307 : }
4308 : else {
4309 1 : if (nh->nh_dev) {
4310 1 : req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
4311 : }
4312 : }
4313 1 : if (nh->nh_flags & NH_FLAG_L3_VXLAN) {
4314 0 : req->nhr_rw_dst_mac_size = VR_ETHER_ALEN;
4315 0 : req->nhr_rw_dst_mac = vr_zalloc(req->nhr_rw_dst_mac_size,
4316 : VR_NEXTHOP_REQ_BMAC_OBJECT);
4317 0 : if (!req->nhr_rw_dst_mac)
4318 0 : return -ENOMEM;
4319 0 : VR_MAC_COPY(req->nhr_rw_dst_mac, nh->nh_vxlan_tun_l3_mac);
4320 : }
4321 0 : } else if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
4322 0 : if (nh->nh_pbb_label != -1) {
4323 0 : req->nhr_label_list_size = 1;
4324 0 : req->nhr_label_list =
4325 0 : vr_zalloc(req->nhr_nh_list_size * sizeof(unsigned int),
4326 : VR_NEXTHOP_REQ_LIST_OBJECT);
4327 0 : if (!req->nhr_label_list)
4328 0 : return -ENOMEM;
4329 0 : req->nhr_label_list[0] = nh->nh_pbb_label;
4330 : }
4331 :
4332 0 : req->nhr_pbb_mac_size = VR_ETHER_ALEN;
4333 0 : req->nhr_pbb_mac = vr_zalloc(req->nhr_pbb_mac_size,
4334 : VR_NEXTHOP_REQ_BMAC_OBJECT);
4335 0 : if (!req->nhr_pbb_mac)
4336 0 : return -ENOMEM;
4337 0 : VR_MAC_COPY(req->nhr_pbb_mac, nh->nh_pbb_mac);
4338 : }
4339 :
4340 5 : break;
4341 : }
4342 :
4343 25 : if (req->nhr_encap_size) {
4344 16 : req->nhr_encap_len = VR_ETHER_HLEN;
4345 16 : req->nhr_encap = vr_zalloc(req->nhr_encap_size,
4346 : VR_NEXTHOP_REQ_ENCAP_OBJECT);
4347 16 : if (req->nhr_encap) {
4348 16 : memcpy(req->nhr_encap, encap,
4349 16 : req->nhr_encap_size);
4350 : } else {
4351 0 : req->nhr_encap_size = 0;
4352 0 : req->nhr_encap_len = 0;
4353 0 : return -ENOMEM;
4354 : }
4355 : }
4356 :
4357 25 : return 0;
4358 : }
4359 :
4360 : static vr_nexthop_req *
4361 25 : vr_nexthop_req_get(struct vr_nexthop *nh)
4362 : {
4363 : vr_nexthop_req *nhr;
4364 :
4365 25 : nhr = vr_zalloc(sizeof(vr_nexthop_req), VR_NEXTHOP_REQ_OBJECT);
4366 25 : if (!nhr)
4367 0 : return NULL;
4368 :
4369 25 : if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
4370 4 : nhr->nhr_encap_oif_id_size = VR_MAX_PHY_INF;
4371 4 : nhr->nhr_encap_oif_id = vr_zalloc(nhr->nhr_encap_oif_id_size *
4372 : sizeof(unsigned int), VR_NEXTHOP_REQ_LIST_OBJECT);
4373 4 : if (!nhr->nhr_encap_oif_id)
4374 0 : goto fail;
4375 :
4376 4 : nhr->nhr_encap_valid_size = VR_MAX_PHY_INF;
4377 4 : nhr->nhr_encap_valid = vr_zalloc(nhr->nhr_encap_valid_size *
4378 : sizeof(unsigned int), VR_NEXTHOP_REQ_LIST_OBJECT);
4379 4 : if (!nhr->nhr_encap_valid)
4380 0 : goto fail;
4381 : } else {
4382 21 : nhr->nhr_encap_oif_id_size = 1;
4383 21 : nhr->nhr_encap_oif_id = vr_zalloc(nhr->nhr_encap_oif_id_size *
4384 : sizeof(unsigned int), VR_NEXTHOP_REQ_LIST_OBJECT);
4385 21 : if (!nhr->nhr_encap_oif_id)
4386 0 : goto fail;
4387 :
4388 21 : nhr->nhr_encap_valid_size = 0;
4389 21 : nhr->nhr_encap_valid = NULL;
4390 : }
4391 25 : if ((nh->nh_type == NH_TUNNEL) &&
4392 5 : (nh->nh_flags & NH_FLAG_TUNNEL_UDP) &&
4393 0 : (nh->nh_family == AF_INET6)) {
4394 0 : nhr->nhr_tun_sip6 = vr_malloc(VR_IP6_ADDRESS_LEN,
4395 : VR_NETWORK_ADDRESS_OBJECT);
4396 0 : if (!nhr->nhr_tun_sip6)
4397 0 : goto fail;
4398 0 : nhr->nhr_tun_sip6_size = VR_IP6_ADDRESS_LEN;
4399 :
4400 0 : nhr->nhr_tun_dip6 = vr_malloc(VR_IP6_ADDRESS_LEN,
4401 : VR_NETWORK_ADDRESS_OBJECT);
4402 0 : if (!nhr->nhr_tun_dip6)
4403 0 : goto fail;
4404 0 : nhr->nhr_tun_dip6_size = VR_IP6_ADDRESS_LEN;
4405 : }
4406 :
4407 25 : return nhr;
4408 :
4409 0 : fail:
4410 0 : if (nhr->nhr_encap_oif_id) {
4411 0 : vr_free(nhr->nhr_encap_oif_id, nhr->nhr_encap_oif_id_size *
4412 : sizeof(unsigned int));
4413 0 : nhr->nhr_encap_oif_id = NULL;
4414 : }
4415 :
4416 0 : if (nhr->nhr_encap_valid) {
4417 0 : vr_free(nhr->nhr_encap_valid, nhr->nhr_encap_valid_size *
4418 : sizeof(unsigned int));
4419 0 : nhr->nhr_encap_valid = NULL;
4420 : }
4421 :
4422 0 : if (nhr->nhr_tun_sip6) {
4423 0 : vr_free(nhr->nhr_tun_sip6, VR_IP6_ADDRESS_LEN);
4424 0 : nhr->nhr_tun_sip6 = NULL;
4425 : }
4426 :
4427 0 : if (nhr->nhr_tun_dip6) {
4428 0 : vr_free(nhr->nhr_tun_dip6, VR_IP6_ADDRESS_LEN);
4429 0 : nhr->nhr_tun_dip6 = NULL;
4430 : }
4431 :
4432 0 : if (nhr) {
4433 0 : vr_free(nhr, VR_NEXTHOP_REQ_OBJECT);
4434 0 : nhr = NULL;
4435 : }
4436 :
4437 0 : return nhr;
4438 : }
4439 :
4440 : static void
4441 25 : vr_nexthop_req_destroy(vr_nexthop_req *req)
4442 : {
4443 25 : if (!req)
4444 0 : return;
4445 :
4446 25 : if (req->nhr_encap_size && req->nhr_encap) {
4447 16 : vr_free(req->nhr_encap, VR_NEXTHOP_REQ_ENCAP_OBJECT);
4448 16 : req->nhr_encap_size = 0;
4449 16 : req->nhr_encap = NULL;
4450 : }
4451 :
4452 25 : if (req->nhr_nh_list_size && req->nhr_nh_list) {
4453 0 : vr_free(req->nhr_nh_list, VR_NEXTHOP_REQ_LIST_OBJECT);
4454 0 : req->nhr_nh_list_size = 0;
4455 0 : req->nhr_nh_list = NULL;
4456 : }
4457 :
4458 25 : if (req->nhr_label_list_size && req->nhr_label_list) {
4459 0 : vr_free(req->nhr_label_list, VR_NEXTHOP_REQ_LIST_OBJECT);
4460 0 : req->nhr_label_list = NULL;
4461 0 : req->nhr_label_list_size = 0;
4462 : }
4463 :
4464 25 : if (req->nhr_tun_sip6) {
4465 0 : vr_free(req->nhr_tun_sip6, VR_NETWORK_ADDRESS_OBJECT);
4466 0 : req->nhr_tun_sip6 = NULL;
4467 : }
4468 :
4469 25 : if (req->nhr_tun_dip6) {
4470 0 : vr_free(req->nhr_tun_dip6, VR_NETWORK_ADDRESS_OBJECT);
4471 0 : req->nhr_tun_dip6 = NULL;
4472 : }
4473 :
4474 25 : if (req->nhr_pbb_mac) {
4475 0 : vr_free(req->nhr_pbb_mac, VR_NEXTHOP_REQ_BMAC_OBJECT);
4476 0 : req->nhr_pbb_mac = NULL;
4477 0 : req->nhr_pbb_mac_size = 0;
4478 : }
4479 :
4480 25 : if (req->nhr_encap_oif_id_size && req->nhr_encap_oif_id) {
4481 25 : vr_free(req->nhr_encap_oif_id, VR_NEXTHOP_REQ_LIST_OBJECT);
4482 25 : req->nhr_encap_oif_id = NULL;
4483 25 : req->nhr_encap_oif_id_size = 0;
4484 : }
4485 :
4486 25 : if (req->nhr_encap_valid_size && req->nhr_encap_valid) {
4487 4 : vr_free(req->nhr_encap_valid, VR_NEXTHOP_REQ_LIST_OBJECT);
4488 4 : req->nhr_encap_valid = NULL;
4489 4 : req->nhr_encap_valid_size = 0;
4490 : }
4491 :
4492 25 : vr_free(req, VR_NEXTHOP_REQ_OBJECT);
4493 25 : return;
4494 : }
4495 :
4496 : int
4497 25 : vr_nexthop_get(vr_nexthop_req *req)
4498 : {
4499 25 : int ret = 0;
4500 25 : struct vr_nexthop *nh = NULL;
4501 : struct vrouter *router;
4502 25 : vr_nexthop_req *resp = NULL;
4503 :
4504 25 : router = vrouter_get(req->nhr_rid);
4505 25 : if (!router || (unsigned int)req->nhr_id >= router->vr_max_nexthops) {
4506 0 : ret = -ENODEV;
4507 0 : goto generate_response;
4508 : }
4509 :
4510 25 : nh = __vrouter_get_nexthop(router, req->nhr_id);
4511 25 : if (nh) {
4512 25 : resp = vr_nexthop_req_get(nh);
4513 25 : if (!resp) {
4514 0 : ret = -ENOMEM;
4515 0 : goto generate_response;
4516 : }
4517 :
4518 25 : resp->h_op = SANDESH_OP_GET;
4519 25 : if (resp)
4520 25 : ret = vr_nexthop_make_req(resp, nh);
4521 : else
4522 0 : ret = -ENOMEM;
4523 : } else
4524 0 : ret = -ENOENT;
4525 :
4526 : /* Debug comparison to check if matching entry is programmed on NIC */
4527 25 : if (!ret)
4528 25 : vr_offload_nexthop_get(nh, resp);
4529 :
4530 0 : generate_response:
4531 25 : vr_message_response(VR_NEXTHOP_OBJECT_ID, ret < 0 ? NULL : resp, ret, false);
4532 25 : if (resp)
4533 25 : vr_nexthop_req_destroy(resp);
4534 :
4535 25 : return 0;
4536 : }
4537 :
4538 : int
4539 0 : vr_nexthop_dump(vr_nexthop_req *r)
4540 : {
4541 0 : int ret = 0;
4542 : unsigned int i;
4543 0 : vr_nexthop_req *resp = NULL;
4544 0 : struct vr_message_dumper *dumper = NULL;
4545 : struct vr_nexthop *nh;
4546 0 : struct vrouter *router = vrouter_get(0);
4547 :
4548 0 : if (!router && (ret = -ENODEV))
4549 0 : goto generate_response;
4550 :
4551 0 : if ((unsigned int)(r->nhr_marker) + 1 >= router->vr_max_nexthops)
4552 0 : goto generate_response;
4553 :
4554 0 : dumper = vr_message_dump_init(r);
4555 0 : if (!dumper && (ret = -ENOMEM))
4556 0 : goto generate_response;
4557 :
4558 0 : for (i = (unsigned int)(r->nhr_marker + 1);
4559 0 : i < router->vr_max_nexthops; i++) {
4560 0 : nh = __vrouter_get_nexthop(router, i);
4561 0 : if (nh) {
4562 0 : resp = vr_nexthop_req_get(nh);
4563 0 : if (!resp && (ret = -ENOMEM))
4564 0 : goto generate_response;
4565 :
4566 0 : resp->h_op = SANDESH_OP_DUMP;
4567 0 : ret = vr_nexthop_make_req(resp, nh);
4568 :
4569 0 : if (!ret)
4570 0 : vr_offload_nexthop_get(nh, resp);
4571 :
4572 0 : if ((ret < 0) || ((ret = vr_message_dump_object(dumper,
4573 : VR_NEXTHOP_OBJECT_ID, resp)) <= 0)) {
4574 0 : vr_nexthop_req_destroy(resp);
4575 0 : break;
4576 : }
4577 :
4578 0 : vr_nexthop_req_destroy(resp);
4579 : }
4580 : }
4581 :
4582 0 : generate_response:
4583 0 : vr_message_dump_exit(dumper, ret);
4584 0 : return 0;
4585 : }
4586 :
4587 : /*
4588 : * called by sandesh_process based on type of the request
4589 : */
4590 : void
4591 569 : vr_nexthop_req_process(void *s_req)
4592 : {
4593 : int ret;
4594 569 : vr_nexthop_req *req = (vr_nexthop_req *)s_req;
4595 :
4596 569 : switch (req->h_op) {
4597 277 : case SANDESH_OP_ADD:
4598 277 : ret = vr_nexthop_add(req);
4599 277 : break;
4600 :
4601 25 : case SANDESH_OP_GET:
4602 25 : ret = vr_nexthop_get(req);
4603 25 : break;
4604 :
4605 267 : case SANDESH_OP_DEL:
4606 267 : ret = vr_nexthop_delete(req);
4607 267 : break;
4608 :
4609 0 : case SANDESH_OP_DUMP:
4610 0 : ret = vr_nexthop_dump(req);
4611 0 : break;
4612 :
4613 0 : default:
4614 0 : ret = -EOPNOTSUPP;
4615 0 : vr_send_response(ret);
4616 0 : break;
4617 : }
4618 569 : }
4619 :
4620 : int
4621 8 : vr_is_local_ecmp_nh (struct vr_nexthop *nh)
4622 : {
4623 : int i;
4624 :
4625 8 : if (!nh || (nh->nh_type != NH_COMPOSITE) ||
4626 0 : (!(nh->nh_flags & NH_FLAG_COMPOSITE_ECMP))) {
4627 8 : return 0;
4628 : }
4629 0 : for (i = 0; i < nh->nh_component_cnt; i++) {
4630 0 : if (nh->nh_component_nh && nh->nh_component_nh[i].cnh &&
4631 0 : nh->nh_component_nh[i].cnh->nh_type != NH_ENCAP) {
4632 0 : return 0;
4633 : }
4634 : }
4635 0 : return 1;
4636 : }
4637 :
4638 : struct vr_interface *
4639 0 : vr_get_ecmp_first_member_dev (struct vr_nexthop *nh)
4640 : {
4641 : int i;
4642 0 : if (!nh || (nh->nh_type != NH_COMPOSITE) ||
4643 0 : (!(nh->nh_flags & NH_FLAG_COMPOSITE_ECMP))) {
4644 0 : return NULL;
4645 : }
4646 :
4647 0 : for (i = 0; i < nh->nh_component_cnt; i++) {
4648 0 : if (nh->nh_component_nh && nh->nh_component_nh[i].cnh) {
4649 0 : return nh->nh_component_nh[i].cnh ? nh->nh_component_nh[i].cnh->nh_dev : NULL;
4650 : }
4651 : }
4652 0 : return NULL;
4653 : }
4654 :
4655 : static void
4656 53 : nh_table_exit(struct vrouter *router, bool soft_reset)
4657 : {
4658 : unsigned int i;
4659 : struct vr_nexthop *nh;
4660 :
4661 53 : if (!router->vr_nexthops)
4662 0 : return;
4663 :
4664 27787317 : for (i = 0; i < router->vr_max_nexthops; i++) {
4665 27787264 : if (soft_reset && i == NH_DISCARD_ID)
4666 0 : continue;
4667 27787264 : nh = __vrouter_get_nexthop(router, i);
4668 27787264 : if (nh)
4669 54 : nh->nh_destructor(nh);
4670 : }
4671 :
4672 :
4673 53 : if (soft_reset == false) {
4674 : /* Make the default nh point to NULL */
4675 53 : ip4_default_nh = NULL;
4676 53 : vr_btable_free(router->vr_nexthops);
4677 53 : router->vr_max_nexthops = 0;
4678 53 : router->vr_nexthops = NULL;
4679 : }
4680 :
4681 53 : return;
4682 : }
4683 :
4684 : static int
4685 53 : nh_allocate_discard(void)
4686 : {
4687 53 : ip4_default_nh = vr_zalloc(sizeof(struct vr_nexthop), VR_NEXTHOP_OBJECT);
4688 53 : if (!ip4_default_nh)
4689 0 : return -ENOMEM;
4690 :
4691 53 : ip4_default_nh->nh_id = NH_DISCARD_ID;
4692 53 : ip4_default_nh->nh_type = NH_DISCARD;
4693 53 : ip4_default_nh->nh_router = vrouter_get(0);
4694 53 : ip4_default_nh->nh_reach_nh = nh_discard;
4695 53 : ip4_default_nh->nh_destructor = nh_del;
4696 53 : ip4_default_nh->nh_flags = NH_FLAG_VALID;
4697 53 : ip4_default_nh->nh_family = AF_INET;
4698 :
4699 53 : return vrouter_add_nexthop(ip4_default_nh);
4700 : }
4701 :
4702 : static int
4703 53 : nh_table_init(struct vrouter *router)
4704 : {
4705 : int ret;
4706 : unsigned int table_memory;
4707 :
4708 53 : if (!router->vr_max_nexthops) {
4709 53 : router->vr_max_nexthops = vr_nexthops;
4710 53 : table_memory = router->vr_max_nexthops * sizeof(struct vr_nexthop *);
4711 53 : router->vr_nexthops = vr_btable_alloc(router->vr_max_nexthops,
4712 : sizeof(struct vr_nexthop *));
4713 53 : if (!router->vr_nexthops)
4714 0 : return vr_module_error(-ENOMEM, __FUNCTION__,
4715 : __LINE__, table_memory);
4716 : }
4717 :
4718 53 : if (!ip4_default_nh) {
4719 53 : ret = nh_allocate_discard();
4720 53 : if (ret)
4721 0 : return vr_module_error(ret, __FUNCTION__, __LINE__, 0);
4722 : }
4723 :
4724 53 : return 0;
4725 : }
4726 :
4727 : void
4728 53 : vr_nexthop_exit(struct vrouter *router, bool soft_reset)
4729 : {
4730 53 : nh_table_exit(router, soft_reset);
4731 53 : return;
4732 : }
4733 :
4734 : int
4735 53 : vr_nexthop_init(struct vrouter *router)
4736 : {
4737 53 : return nh_table_init(router);
4738 : }
4739 :
4740 : /*
4741 : * Called by offload module to update vrfstats with packets which have been
4742 : * offloaded. Expect counters in host byte order.
4743 : */
4744 : int
4745 0 : vr_nexthop_update_offload_vrfstats(uint32_t vrfid, uint32_t num_cntrs,
4746 : uint64_t *cntrs)
4747 : {
4748 : uint64_t *dst_cntr;
4749 0 : struct vr_vrf_stats *stats = NULL;
4750 :
4751 0 : if (!vr_inet_vrf_stats)
4752 0 : return 0;
4753 :
4754 : /* hw offload stats always go to CPU 0 */
4755 0 : stats = vr_inet_vrf_stats(vrfid, 0);
4756 0 : if (stats && num_cntrs <= sizeof(struct vr_vrf_stats) / sizeof(uint64_t)) {
4757 0 : dst_cntr = (uint64_t *)stats;
4758 0 : while (num_cntrs-- > 0)
4759 0 : *dst_cntr++ += *cntrs++;
4760 : }
4761 :
4762 0 : return 0;
4763 : }
|