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