Line data Source code
1 : /*
2 : * vr_datapath.c -- data path inside the router
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : */
6 : #include <vr_os.h>
7 : #include <vr_bridge.h>
8 : #include <vr_packet.h>
9 : #include <vr_interface.h>
10 : #include <vr_datapath.h>
11 : #include <vr_mirror.h>
12 : #include <vr_bridge.h>
13 : #include <vr_packet.h>
14 :
15 : #include "vr_ip_mtrie.h"
16 :
17 : extern unsigned int vr_inet_route_flags(unsigned int, unsigned int);
18 : extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short,
19 : unsigned int);
20 : extern struct vr_nexthop *
21 : vr_inet_src_lookup(unsigned short vrf, struct vr_packet *pkt);
22 :
23 : mac_response_t
24 0 : vr_get_proxy_mac(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
25 : struct vr_route_req *rt, unsigned char *dmac)
26 : {
27 : bool from_fabric, stitched, flood, over_lay, hosted_vm;
28 : bool to_gateway, no_proxy, to_vcp;
29 :
30 : unsigned char *resp_mac;
31 0 : struct vr_nexthop *nh = NULL, *l3_nh = NULL;
32 0 : struct vr_interface *vif = pkt->vp_if;
33 0 : struct vr_vrf_stats *stats = NULL;
34 :
35 0 : over_lay = true;
36 0 : from_fabric = stitched = flood = hosted_vm = false;
37 0 : to_gateway = to_vcp = no_proxy = false;
38 :
39 0 : if (vr_inet_vrf_stats)
40 0 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
41 : /* here we will not check for stats, but will check before use */
42 :
43 0 : if (vif->vif_flags & VIF_FLAG_MAC_PROXY) {
44 0 : resp_mac = vif->vif_mac;
45 0 : goto proxy_selected;
46 : }
47 :
48 0 : if (vif->vif_type == VIF_TYPE_PHYSICAL)
49 0 : from_fabric = true;
50 :
51 0 : if (vif->vif_flags & VIF_FLAG_NO_ARP_PROXY)
52 0 : no_proxy = true;
53 :
54 0 : if (rt->rtr_req.rtr_label_flags & VR_RT_ARP_FLOOD_FLAG)
55 0 : flood = true;
56 :
57 0 : if (vif_is_vhost(vif) || (from_fabric && (fmd->fmd_label == -1) &&
58 0 : (fmd->fmd_dvrf == vif->vif_vrf)))
59 0 : over_lay = false;
60 :
61 0 : if (vr_gateway_nexthop(rt->rtr_nh))
62 0 : to_gateway = true;
63 :
64 : /*
65 : * the no_proxy flag is set for the vcp ports. From such ports
66 : * vrouter should proxy only for the gateway ip.
67 : */
68 0 : if (no_proxy && !to_gateway)
69 0 : return MR_DROP;
70 :
71 0 : if (from_fabric) {
72 0 : if (vr_nexthop_is_vcp(rt->rtr_nh)) {
73 0 : to_vcp = true;
74 : }
75 : }
76 :
77 :
78 0 : l3_nh = rt->rtr_nh;
79 0 : resp_mac = vif->vif_mac;
80 0 : if (rt->rtr_req.rtr_index != VR_BE_INVALID_INDEX) {
81 0 : if ((nh = vr_bridge_lookup(fmd->fmd_dvrf, rt))) {
82 0 : resp_mac = rt->rtr_req.rtr_mac;
83 0 : stitched = true;
84 : }
85 : }
86 :
87 0 : if (!over_lay)
88 0 : nh = l3_nh;
89 :
90 0 : if (vr_hosted_nexthop(nh))
91 0 : hosted_vm = true;
92 :
93 :
94 : /*
95 : * situations that are handled here (from_fabric)
96 : *
97 : * . arp request from vm, but not proxied at the source because of lack
98 : * of information at the source. only the compute that hosts the
99 : * destination should respond, and that too only if the mac information
100 : * is present (and hence the ENCAP check).
101 : *
102 : * . arp request from a baremetal arriving at a TSN, which if posesses the
103 : * mac information for the destination vm, should proxy. If it does not
104 : * hold the mac information, the request should be flooded
105 : *
106 : * . arp request from the uplink port of a vcp
107 : */
108 0 : if (from_fabric) {
109 0 : if (flood && !stitched) {
110 0 : if (stats)
111 0 : stats->vrf_arp_physical_flood++;
112 0 : return MR_FLOOD;
113 : }
114 :
115 : /*
116 : * arp requests to gateway coming from the fabric should be dropped
117 : * unless the request was for the TSN DNS service (which appears as
118 : * the gateway, with the current set of checks). We should not respond
119 : * for gateway ip if we are TSN and the request came from baremetal.
120 : * TSN does not have gateway route and hence the to_gateway will be
121 : * true only for the DNS ip.
122 : */
123 0 : if (to_gateway) {
124 0 : if ((fmd->fmd_src != TOR_SOURCE) && (fmd->fmd_src !=
125 : TOR_EVPN_SOURCE)) {
126 0 : return MR_DROP;
127 : }
128 : }
129 :
130 : /*
131 : * we should proxy if the vm is hosted by us, in which case nh will be
132 : * of ENCAP type. we should also proxy for a host in vcp port. In all
133 : * other cases, we should proxy only if
134 : *
135 : * i am a TSN(fmd->fmd_src),
136 : * i amd the dns IP or
137 : * i have the mac information (nh - (mostly tunnel)) and
138 : * the originator is a bare metal (fmd->fmd_src)
139 : */
140 0 : if (to_vcp || to_gateway || hosted_vm ||
141 0 : (fmd->fmd_src == TOR_SOURCE) ||
142 0 : (fmd->fmd_src == TOR_EVPN_SOURCE)) {
143 0 : if (stats)
144 0 : stats->vrf_arp_physical_stitch++;
145 : } else {
146 0 : if (stats)
147 0 : stats->vrf_arp_physical_flood++;
148 :
149 0 : if (!over_lay)
150 0 : return MR_XCONNECT;
151 :
152 0 : return MR_FLOOD;
153 : }
154 0 : } else if (!vif_is_vhost(vif)) {
155 :
156 0 : proxy_selected:
157 0 : if (!stitched && flood) {
158 : /*
159 : * if there is no stitching information, but flood flag is set
160 : * we should flood
161 : */
162 0 : if (stats)
163 0 : stats->vrf_arp_virtual_flood++;
164 0 : return MR_FLOOD;
165 : }
166 :
167 0 : if (stats) {
168 0 : if (stitched) {
169 0 : stats->vrf_arp_virtual_stitch++;
170 : } else {
171 0 : fmd->fmd_flags |= FMD_FLAG_MAC_IS_MY_MAC;
172 0 : stats->vrf_arp_virtual_proxy++;
173 : }
174 : }
175 : }
176 :
177 0 : VR_MAC_COPY(dmac, resp_mac);
178 :
179 0 : return MR_PROXY;
180 : }
181 :
182 : static void
183 0 : vr_arp_proxy(struct vr_arp *sarp, struct vr_packet *pkt,
184 : struct vr_forwarding_md *fmd, unsigned char *dmac)
185 : {
186 : struct vr_eth *eth;
187 : struct vr_arp *arp;
188 :
189 0 : eth = (struct vr_eth *)pkt_push(pkt, sizeof(*eth));
190 0 : if (!eth) {
191 0 : PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_DATAPATH_C, __LINE__);
192 0 : vr_pfree(pkt, VP_DROP_PUSH);
193 0 : return;
194 : }
195 :
196 0 : memcpy(eth->eth_dmac, sarp->arp_sha, VR_ETHER_ALEN);
197 0 : memcpy(eth->eth_smac, dmac, VR_ETHER_ALEN);
198 0 : eth->eth_proto = htons(VR_ETH_PROTO_ARP);
199 :
200 0 : arp = (struct vr_arp *)(pkt_data(pkt) + sizeof(*eth));
201 0 : arp->arp_hw = htons(VR_ARP_HW_TYPE_ETHER);
202 0 : arp->arp_proto = htons(VR_ETH_PROTO_IP);
203 0 : arp->arp_hwlen = VR_ETHER_ALEN;
204 0 : arp->arp_protolen = VR_IP_ADDRESS_LEN;
205 0 : arp->arp_op = htons(VR_ARP_OP_REPLY);
206 0 : memcpy(arp->arp_sha, dmac, VR_ETHER_ALEN);
207 0 : memcpy(arp->arp_dha, sarp->arp_sha, VR_ETHER_ALEN);
208 0 : memcpy(&arp->arp_dpa, &sarp->arp_spa, sizeof(sarp->arp_spa));
209 0 : memcpy(&arp->arp_spa, &sarp->arp_dpa, sizeof(sarp->arp_dpa));
210 :
211 0 : vr_mac_reply_send(pkt, fmd);
212 :
213 0 : return;
214 : }
215 :
216 : static int
217 6 : vr_handle_arp_request(struct vr_arp *sarp, struct vr_packet *pkt,
218 : struct vr_forwarding_md *fmd, unsigned char *eth_dmac)
219 : {
220 6 : int handled = true;
221 : unsigned char dmac[VR_ETHER_ALEN];
222 : mac_response_t arp_result;
223 :
224 : struct vr_packet *pkt_c;
225 6 : struct vr_interface *vif = pkt->vp_if;
226 6 : VR_MAC_COPY(dmac, eth_dmac);
227 :
228 6 : arp_result = vif->vif_mac_request(vif, pkt, fmd, dmac);
229 6 : switch (arp_result) {
230 0 : case MR_PROXY:
231 0 : vr_arp_proxy(sarp, pkt, fmd, dmac);
232 0 : break;
233 :
234 3 : case MR_XCONNECT:
235 3 : handled = vif_xconnect(pkt->vp_if, pkt, fmd);
236 3 : if (VR_RX_HANDLER_PASS != handled)
237 3 : handled = true;
238 3 : break;
239 :
240 0 : case MR_TRAP_X:
241 0 : pkt_c = vr_pclone(pkt);
242 0 : if (pkt_c) {
243 0 : vr_trap(pkt_c, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
244 0 : handled = vif_xconnect(pkt->vp_if, pkt, fmd);
245 0 : if (VR_RX_HANDLER_PASS != handled)
246 0 : handled = true;
247 : } else {
248 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
249 : }
250 0 : break;
251 :
252 0 : case MR_MIRROR:
253 0 : pkt_c = vr_pclone(pkt);
254 0 : if (pkt_c)
255 0 : vr_trap(pkt_c, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
256 :
257 : /* Flood the original packet*/
258 0 : handled = false;
259 0 : break;
260 :
261 0 : case MR_DROP:
262 0 : PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
263 0 : vr_pfree(pkt, VP_DROP_INVALID_ARP);
264 0 : break;
265 :
266 3 : case MR_FLOOD:
267 : default:
268 : /*
269 : * If the packet is from Service Instance VM, we dont flood the
270 : * packet any where
271 : */
272 3 : if (!vif_is_service(pkt->vp_if)) {
273 3 : handled = false;
274 : } else {
275 0 : PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
276 0 : vr_pfree(pkt, VP_DROP_INVALID_ARP);
277 : }
278 3 : break;
279 :
280 : }
281 :
282 6 : return handled;
283 : }
284 :
285 : /*
286 : * ARP responses
287 : * on fabric network: Both kernel and Agent are interested
288 : * on fabric interface for VN : not handled
289 : * from Virtual interface: If destined "to me" - trap to Agent
290 : * else flood as well
291 : *
292 : */
293 : static int
294 0 : vr_handle_arp_reply(struct vr_arp *sarp, struct vr_packet *pkt,
295 : struct vr_forwarding_md *fmd)
296 : {
297 0 : struct vr_interface *vif = pkt->vp_if;
298 : struct vr_packet *cloned_pkt;
299 0 : int handled = 1;
300 :
301 : /*
302 : * If Vhost or fabric in cross connct mode, simply cross connect the
303 : * packet
304 : */
305 0 : if (vif_mode_xconnect(vif) || vif->vif_type == VIF_TYPE_HOST) {
306 0 : handled = vif_xconnect(vif, pkt, fmd);
307 0 : if (VR_RX_HANDLER_PASS != handled)
308 0 : handled = 1;
309 0 : return handled;
310 : }
311 :
312 0 : if (vif_is_virtual(vif)) {
313 :
314 : /*
315 : * If packet is destined "to me": packet is just trapped to
316 : * Agent. If multicast: paket would be Trapped and marked as
317 : * unhandled, so that caller continues to do original action. If
318 : * unicast, and not destined "to me" it is a case of unknown
319 : * unicast, and is not trapped to agent and caller takes the
320 : * aciton
321 : */
322 :
323 0 : if (fmd->fmd_to_me) {
324 0 : cloned_pkt = pkt;
325 0 : } else if (pkt->vp_flags & VP_FLAG_MULTICAST) {
326 0 : cloned_pkt = vr_pclone(pkt);
327 :
328 : /* If cloning fails, just trap original */
329 0 : if (cloned_pkt)
330 0 : handled = 0;
331 : else
332 0 : cloned_pkt = pkt;
333 : } else {
334 0 : return !handled;
335 : }
336 :
337 : /* If destined to me, Agent is interested in it */
338 0 : vr_preset(cloned_pkt);
339 0 : vr_trap(cloned_pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
340 0 : return handled;
341 : }
342 :
343 0 : if (vif_is_fabric(vif)) {
344 :
345 : /* If a tunneled packet, dont handle */
346 0 : if (fmd->fmd_label >= 0)
347 0 : return !handled;
348 :
349 : /*
350 : * in gro cases, fmd label won't be set. Hence, resort to the
351 : * following check to identify whether the packet was tunneled
352 : */
353 0 : if (fmd->fmd_dvrf != vif->vif_vrf)
354 0 : return !handled;
355 :
356 : /* If fabric: Agent and kernel are interested in it */
357 0 : cloned_pkt = pkt_cow(pkt, AGENT_PKT_HEAD_SPACE);
358 0 : if (cloned_pkt) {
359 0 : vr_preset(cloned_pkt);
360 0 : handled = vif_xconnect(vif, pkt, fmd);
361 0 : if (VR_RX_HANDLER_PASS != handled)
362 0 : handled = 1;
363 0 : vr_trap(cloned_pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
364 : } else {
365 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
366 : }
367 :
368 0 : return handled;
369 : }
370 :
371 : /* Any other Response can be dropped */
372 0 : PKT_LOG(VP_DROP_INVALID_IF, pkt, 0, VR_DATAPATH_C, __LINE__);
373 0 : vr_pfree(pkt, VP_DROP_INVALID_IF);
374 :
375 0 : return handled;
376 : }
377 :
378 : /*
379 : * handle unicast arp requests and neighbor refreshes. In many cases,
380 : * we wouldn't like the unicast arp requests from gateway (such as MX)
381 : * to reach the VMs and change the gateway mac to ip(6) binding, since
382 : * for vms the gateway is always agent. We would like such requests
383 : * to go only if the mode is l2
384 : */
385 : int
386 60 : vif_plug_mac_request(struct vr_interface *vif, struct vr_packet *pkt,
387 : struct vr_forwarding_md *fmd)
388 : {
389 60 : int nheader, handled = 1;
390 : unsigned char eth_dmac[VR_ETHER_ALEN];
391 :
392 60 : if (pkt->vp_flags & VP_FLAG_MULTICAST)
393 0 : goto unhandled;
394 :
395 60 : nheader = pkt_network_header(pkt) - pkt_data(pkt);
396 60 : if (nheader < 0 || (pkt->vp_data + nheader > pkt->vp_end))
397 0 : goto unhandled;
398 :
399 60 : VR_MAC_COPY(eth_dmac, pkt_data(pkt));
400 :
401 60 : if (pkt->vp_type == VP_TYPE_ARP) {
402 0 : if (pkt->vp_len < (nheader + sizeof(struct vr_arp)))
403 0 : goto unhandled;
404 :
405 0 : pkt_pull(pkt, nheader);
406 :
407 0 : handled = vr_arp_input(pkt, fmd, eth_dmac);
408 0 : if (!handled) {
409 0 : pkt_push(pkt, nheader);
410 : }
411 0 : return handled;
412 60 : } else if (pkt->vp_type == VP_TYPE_IP6) {
413 5 : if (pkt->vp_len < (nheader + sizeof(struct vr_ip6) +
414 : sizeof(struct vr_icmp) + VR_IP6_ADDRESS_LEN +
415 5 : sizeof(struct vr_neighbor_option) + VR_ETHER_ALEN))
416 5 : goto unhandled;
417 :
418 0 : pkt_pull(pkt, nheader);
419 :
420 0 : handled = vr_neighbor_input(pkt, fmd, eth_dmac);
421 0 : if (!handled) {
422 0 : pkt_push(pkt, nheader);
423 : }
424 0 : return handled;
425 : }
426 :
427 55 : unhandled:
428 60 : return !handled;
429 : }
430 :
431 : void
432 0 : vr_mac_reply_send(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
433 : {
434 0 : bool vif_tx = false;
435 : struct vr_forwarding_md fmd_new;
436 : struct vr_route_req rt;
437 0 : struct vr_nexthop *nh = NULL;
438 0 : struct vr_interface *vif = pkt->vp_if;
439 :
440 0 : vr_init_forwarding_md(&fmd_new);
441 0 : fmd_new.fmd_dvrf = fmd->fmd_dvrf;
442 0 : vr_pkt_type(pkt, 0, &fmd_new);
443 :
444 : /* Disable the flow processing for response packets */
445 0 : pkt->vp_flags |= VP_FLAG_FLOW_SET;
446 :
447 : /*
448 : * XXX: for vcp ports, there won't be bridge table entries. to avoid
449 : * doing vr_bridge_input, we check for the flag NO_ARP_PROXY and
450 : * and if set, directly send out on that interface
451 : * Incase of service instance with scaling of more than one, reply
452 : * can not be bridged as the destination mac address might point to
453 : * any of the primary/secondary. In this case, reply is forced
454 : * to go on the receiving VIF
455 : * If ARP request is received on fabric, reply on the same interface
456 : * only if vrf is 0 (underlay network)
457 : */
458 0 : if (vif_is_vhost(vif) || (vif_is_fabric(vif) && (fmd->fmd_dvrf == 0)) ||
459 0 : (vif->vif_flags & (VIF_FLAG_NO_ARP_PROXY | VIF_FLAG_MAC_PROXY))) {
460 0 : vif_tx = true;
461 : } else {
462 0 : rt.rtr_req.rtr_label_flags = 0;
463 0 : rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX;
464 0 : rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN;
465 0 : rt.rtr_req.rtr_mac = pkt_data(pkt);
466 0 : rt.rtr_req.rtr_vrf_id = fmd_new.fmd_dvrf;
467 0 : nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt);
468 0 : if (!nh || !(nh->nh_flags & NH_FLAG_VALID)) {
469 0 : PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_DATAPATH_C, __LINE__);
470 0 : vr_pfree(pkt, VP_DROP_INVALID_NH);
471 0 : return;
472 : }
473 0 : if (rt.rtr_req.rtr_label_flags & VR_BE_LABEL_VALID_FLAG)
474 0 : fmd_new.fmd_label = rt.rtr_req.rtr_label;
475 :
476 0 : if (vif_is_virtual(vif) && (nh->nh_dev != vif)) {
477 0 : vif_tx = true;
478 : }
479 : }
480 :
481 0 : if (vif_tx)
482 0 : vif->vif_tx(vif, pkt, &fmd_new);
483 : else
484 0 : nh_output(pkt, nh, &fmd_new);
485 :
486 0 : return;
487 : }
488 :
489 :
490 : /*
491 : * This funciton parses the ethernet packet and assigns the
492 : * pkt->vp_type, network protocol of the packet. The ethernet header can
493 : * start from an offset from vp_data
494 : */
495 : int
496 161 : vr_pkt_type(struct vr_packet *pkt, unsigned short offset,
497 : struct vr_forwarding_md *fmd)
498 : {
499 161 : unsigned char *eth = pkt_data(pkt) + offset;
500 : unsigned short eth_proto;
501 161 : int pull_len, pkt_len = pkt_head_len(pkt) - offset;
502 : struct vr_vlan_hdr *vlan;
503 :
504 161 : pull_len = VR_ETHER_HLEN;
505 161 : if (pkt_len < pull_len)
506 0 : return -1;
507 :
508 161 : pkt->vp_flags &= ~(VP_FLAG_MULTICAST);
509 :
510 : /* L2 broadcast/multicast packets are multicast packets */
511 161 : if (IS_MAC_BMCAST(eth))
512 9 : pkt->vp_flags |= VP_FLAG_MULTICAST;
513 :
514 161 : eth_proto = ntohs(*(unsigned short *)(eth + VR_ETHER_PROTO_OFF));
515 161 : if (eth_proto == VR_ETH_PROTO_PBB) {
516 :
517 0 : if (pkt_len < (pull_len + sizeof(struct vr_pbb_itag)))
518 0 : return -1;
519 0 : pull_len += sizeof(struct vr_pbb_itag);
520 :
521 0 : if (pkt_len < (pull_len + VR_ETHER_HLEN))
522 0 : return -1;
523 :
524 0 : pkt->vp_type = vr_eth_proto_to_pkt_type(eth_proto);
525 0 : return 0;
526 : }
527 :
528 161 : while (eth_proto == VR_ETH_PROTO_VLAN) {
529 0 : if (pkt_len < (pull_len + sizeof(*vlan)))
530 0 : return -1;
531 0 : vlan = (struct vr_vlan_hdr *)(eth + pull_len);
532 : /*
533 : * consider the packet as vlan tagged only if it is provider
534 : * vlan tag. Customers vlan tag, Vrouter is not bothered off
535 : */
536 0 : if (fmd && (fmd->fmd_vlan == VLAN_ID_INVALID))
537 0 : fmd->fmd_vlan = ntohs(vlan->vlan_tag) & 0xFFF;
538 0 : eth_proto = ntohs(vlan->vlan_proto);
539 0 : pull_len += sizeof(*vlan);
540 : }
541 :
542 :
543 161 : pkt_set_network_header(pkt, pkt->vp_data + offset + pull_len);
544 161 : pkt_set_inner_network_header(pkt, pkt->vp_data + offset + pull_len);
545 161 : pkt->vp_type = vr_eth_proto_to_pkt_type(eth_proto);
546 :
547 161 : return 0;
548 : }
549 :
550 : int
551 7 : vr_arp_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
552 : unsigned char *eth_dmac)
553 : {
554 7 : int handled = 1;
555 : struct vr_arp sarp;
556 :
557 7 : if (pkt->vp_type != VP_TYPE_ARP)
558 0 : return !handled;
559 :
560 7 : if (pkt->vp_len < sizeof(struct vr_arp)) {
561 1 : PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
562 1 : vr_pfree(pkt, VP_DROP_INVALID_ARP);
563 1 : return handled;
564 : }
565 :
566 6 : memcpy(&sarp, pkt_data(pkt), sizeof(struct vr_arp));
567 :
568 : /* Validate the arp pkt */
569 6 : if (((htons(sarp.arp_hw) == VR_ARP_HW_TYPE_ETHER) &&
570 6 : (sarp.arp_hwlen != VR_ARP_HW_LEN)) ||
571 6 : ((htons(sarp.arp_proto) == VR_ETH_PROTO_IP) &&
572 6 : (sarp.arp_protolen != VR_ARP_PROTO_LEN_IPV4))) {
573 0 : PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
574 0 : vr_pfree(pkt, VP_DROP_INVALID_ARP);
575 0 : return handled;
576 : }
577 :
578 6 : switch (ntohs(sarp.arp_op)) {
579 6 : case VR_ARP_OP_REQUEST:
580 6 : return vr_handle_arp_request(&sarp, pkt, fmd, eth_dmac);
581 :
582 0 : case VR_ARP_OP_REPLY:
583 0 : return vr_handle_arp_reply(&sarp, pkt, fmd);
584 : break;
585 :
586 0 : default:
587 0 : PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
588 0 : vr_pfree(pkt, VP_DROP_INVALID_ARP);
589 : }
590 :
591 0 : return handled;
592 : }
593 :
594 : int
595 14 : vr_trap(struct vr_packet *pkt, unsigned short trap_vrf,
596 : unsigned short trap_reason, void *trap_param)
597 : {
598 14 : struct vr_interface *vif = pkt->vp_if;
599 14 : struct vrouter *router = vif->vif_router;
600 : struct agent_send_params params;
601 :
602 14 : if (router->vr_agent_if && router->vr_agent_if->vif_send) {
603 11 : params.trap_vrf = trap_vrf;
604 11 : params.trap_reason = trap_reason;
605 11 : params.trap_param = trap_param;
606 11 : return router->vr_agent_if->vif_send(router->vr_agent_if, pkt,
607 : ¶ms);
608 : } else {
609 3 : PKT_LOG(VP_DROP_TRAP_NO_IF, pkt, 0, VR_DATAPATH_C, __LINE__);
610 3 : vr_pfree(pkt, VP_DROP_TRAP_NO_IF);
611 : }
612 :
613 3 : return 0;
614 : }
615 :
616 : unsigned int
617 9 : vr_reinject_packet(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
618 : {
619 9 : struct vr_interface *vif = pkt->vp_if;
620 : int handled;
621 :
622 9 : if (pkt->vp_nh) {
623 : /* If nexthop does not have valid data, drop it */
624 1 : if (!(pkt->vp_nh->nh_flags & NH_FLAG_VALID)) {
625 0 : PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_DATAPATH_C, __LINE__);
626 0 : vr_pfree(pkt, VP_DROP_INVALID_NH);
627 0 : return 0;
628 : }
629 :
630 1 : return pkt->vp_nh->nh_reach_nh(pkt, pkt->vp_nh, fmd);
631 : }
632 :
633 8 : if (vif_is_vhost(vif) ||
634 8 : (vif_is_fabric(vif) && (fmd->fmd_label < 0))) {
635 0 : handled = vr_l3_input(pkt, fmd);
636 0 : if (!handled)
637 0 : vif_drop_pkt(vif, pkt, 1);
638 0 : return 0;
639 : }
640 :
641 :
642 8 : return vr_bridge_input(vif->vif_router, pkt, fmd);
643 : }
644 :
645 : /*
646 : * vr_interface_input() is invoked if a packet ingresses an interface.
647 : * This function demultiplexes the packet to right input
648 : * function depending on the protocols enabled on the VIF
649 : */
650 : unsigned int
651 127 : vr_virtual_input(unsigned short vrf, struct vr_interface *vif,
652 : struct vr_packet *pkt, struct vr_forwarding_md *fmd,
653 : unsigned short vlan_id)
654 : {
655 : struct vr_nexthop *nh;
656 : struct vr_eth *eth;
657 : struct vr_route_req vr_req;
658 127 : struct vr_rtable *rtable = NULL;
659 : uint32_t rt_prefix[4];
660 : struct vr_arp *arp;
661 : struct vrouter *router;
662 : uint8_t ip6_nxt;
663 : struct vr_ip6 *ip6;
664 : unsigned short *t_hdr;
665 : struct vr_icmp *icmph;
666 127 : bool check_trap_macipl = false;
667 127 : unsigned int ret = 0;
668 :
669 127 : fmd->fmd_vlan = vlan_id;
670 127 : fmd->fmd_dvrf = vrf;
671 127 : if (pkt->vp_priority != VP_PRIORITY_INVALID) {
672 0 : fmd->fmd_dotonep = pkt->vp_priority;
673 0 : pkt->vp_priority = VP_PRIORITY_INVALID;
674 : }
675 :
676 127 : if (vr_pkt_type(pkt, 0, fmd) < 0) {
677 0 : vif_drop_pkt(vif, pkt, 1);
678 0 : return 0;
679 : }
680 :
681 : /*
682 : * we really do not allow any broadcast packets from interfaces
683 : * that are part of transparent service chain, since transparent
684 : * service chain bridges packets across vrf (and hence loops can
685 : * happen)
686 : */
687 127 : if ((pkt->vp_flags & VP_FLAG_MULTICAST) &&
688 1 : (vif_is_service(vif)) && (pkt->vp_type != VP_TYPE_ARP)) {
689 0 : vif_drop_pkt(vif, pkt, 1);
690 0 : return 0;
691 : }
692 :
693 127 : if (!fmd->fmd_to_me) {
694 127 : eth = (struct vr_eth *)pkt_data(pkt);
695 127 : router = vrouter_get(0);
696 :
697 127 : if ((pkt->vp_if->vif_flags & VIF_FLAG_MAC_IP_LEARNING) &&
698 12 : (pkt->vp_if->vif_flags & VIF_FLAG_L3_ENABLED) &&
699 10 : (pkt->vp_if->vif_flags & VIF_FLAG_L2_ENABLED)){
700 :
701 10 : memset(&vr_req, 0, sizeof(struct vr_route_req));
702 10 : rtable = router->vr_inet_rtable;
703 10 : vr_req.rtr_req.rtr_prefix = (uint8_t*)&rt_prefix;
704 :
705 10 : if(pkt->vp_type == VP_TYPE_ARP) {
706 5 : vr_req.rtr_req.rtr_prefix_size = 4;
707 5 : vr_req.rtr_req.rtr_prefix_len = IP4_PREFIX_LEN;
708 5 : vr_req.rtr_req.rtr_family = AF_INET;
709 5 : arp = (struct vr_arp *)(pkt_data(pkt) + sizeof(struct vr_eth));
710 :
711 5 : memcpy(vr_req.rtr_req.rtr_prefix, (uint8_t *)&arp->arp_spa,
712 : sizeof(arp->arp_spa));
713 :
714 5 : rtable->algo_get(fmd->fmd_dvrf, &vr_req);
715 5 : check_trap_macipl = true;
716 : }
717 :
718 10 : if(pkt->vp_type == VP_TYPE_IP6){
719 5 : ip6 = (struct vr_ip6 *)(pkt_data(pkt) + sizeof(struct vr_eth));
720 5 : t_hdr = (unsigned short *)((char *)ip6 + sizeof(struct vr_ip6));
721 5 : ip6_nxt = ip6->ip6_nxt;
722 5 : if(ip6_nxt == VR_IP_PROTO_ICMP6) {
723 5 : icmph = (struct vr_icmp *)t_hdr;
724 5 : if((icmph->icmp_type == VR_ICMP6_TYPE_NEIGH_SOL) ||
725 4 : (icmph->icmp_type == VR_ICMP6_TYPE_NEIGH_AD)){
726 5 : vr_req.rtr_req.rtr_prefix_size = sizeof(ip6->ip6_src);
727 5 : vr_req.rtr_req.rtr_prefix_len = IP6_PREFIX_LEN;
728 5 : vr_req.rtr_req.rtr_family = AF_INET6;
729 5 : memcpy(vr_req.rtr_req.rtr_prefix, ip6->ip6_src,
730 : sizeof(ip6->ip6_src));
731 5 : rtable->algo_get(fmd->fmd_dvrf, &vr_req);
732 5 : check_trap_macipl = true;
733 : }
734 : }
735 : }
736 :
737 10 : if(check_trap_macipl){
738 10 : if(vr_req.rtr_nh && vr_req.rtr_nh->nh_id) {
739 8 : if((pkt->vp_type == VP_TYPE_ARP &&
740 4 : vr_req.rtr_req.rtr_prefix_len != IP4_PREFIX_LEN) ||
741 8 : (pkt->vp_type == VP_TYPE_IP6 &&
742 4 : vr_req.rtr_req.rtr_prefix_len != IP6_PREFIX_LEN) ||
743 8 : ((vr_req.rtr_req.rtr_mac != NULL) &&
744 4 : !(VR_MAC_CMP(eth->eth_smac, vr_req.rtr_req.rtr_mac)))) {
745 2 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_MAC_IP_LEARNING,
746 : NULL);
747 2 : return 0;
748 6 : } else if (vr_req.rtr_req.rtr_mac == NULL) {
749 : /* Incase of gatewayless forwarding, rtr_mac is NULL,
750 : * So comparing source mac with nh encap data and trap
751 : * to agent */
752 4 : nh = vrouter_get_nexthop(0, vr_req.rtr_nh->nh_id);
753 4 : if(nh && !(VR_MAC_CMP(eth->eth_smac, (nh->nh_data )))) {
754 2 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_MAC_IP_LEARNING,
755 : NULL);
756 2 : return 0;
757 : }
758 : }
759 : } else {
760 2 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_MAC_IP_LEARNING, NULL);
761 2 : return 0;
762 : }
763 : }
764 : }
765 :
766 121 : if ((pkt->vp_if->vif_flags & VIF_FLAG_MAC_IP_LEARNING) &&
767 6 : (pkt->vp_if->vif_flags & VIF_FLAG_L2_ENABLED) &&
768 6 : !(pkt->vp_if->vif_flags & VIF_FLAG_L3_ENABLED)) {
769 2 : if(pkt->vp_type == VP_TYPE_ARP) {
770 2 : nh = __vrouter_bridge_lookup(fmd->fmd_dvrf, eth->eth_smac);
771 2 : if(!nh) {
772 1 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_MAC_IP_LEARNING, NULL);
773 1 : return 0;
774 : }
775 : }
776 : }
777 :
778 : }
779 :
780 120 : if (!vr_flow_forward(pkt->vp_if->vif_router, pkt, fmd))
781 19 : return 0;
782 :
783 101 : ret = vr_bridge_input(vif->vif_router, pkt, fmd);
784 :
785 101 : return ret;
786 : }
787 :
788 : unsigned int
789 30 : vr_fabric_input(struct vr_interface *vif, struct vr_packet *pkt,
790 : struct vr_forwarding_md *fmd, unsigned short vlan_id)
791 : {
792 30 : int handled = 0;
793 30 : bool is_ipv6_nd_packet = false;
794 : unsigned short pull_len;
795 : unsigned char *data, eth_dmac[VR_ETHER_ALEN];
796 :
797 30 : if (vr_offload_prepare)
798 30 : vr_offload_prepare(pkt, fmd);
799 30 : fmd->fmd_vlan = vlan_id;
800 30 : fmd->fmd_dvrf = vif->vif_vrf;
801 :
802 30 : if (vr_pkt_type(pkt, 0, fmd) < 0) {
803 0 : vif_drop_pkt(vif, pkt, 1);
804 0 : return 0;
805 : }
806 :
807 30 : if ((pkt->vp_type == VP_TYPE_IP6) && !vr_is_ipv6_underlay_enabled())
808 0 : return vif_xconnect(vif, pkt, fmd);
809 :
810 30 : is_ipv6_nd_packet = vr_is_ipv6_nd_packet(pkt);
811 : /*
812 : * On Fabric ARP packets and IPv6 Neighbor Discovery packets are specially
813 : * handled. Rest all BUM traffic can be cross connected
814 : */
815 30 : if ((pkt->vp_type != VP_TYPE_ARP) && (!is_ipv6_nd_packet) &&
816 17 : (pkt->vp_flags & VP_FLAG_MULTICAST)) {
817 2 : return vif_xconnect(vif, pkt, fmd);
818 : }
819 :
820 28 : data = pkt_data(pkt);
821 28 : pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
822 28 : pkt_pull(pkt, pull_len);
823 :
824 28 : if (pkt->vp_type == VP_TYPE_IP) {
825 14 : handled = vr_l3_input(pkt, fmd);
826 14 : } else if (pkt->vp_type == VP_TYPE_ARP) {
827 3 : VR_MAC_COPY(eth_dmac, data);
828 3 : handled = vr_arp_input(pkt, fmd, eth_dmac);
829 3 : if(VR_RX_HANDLER_PASS == handled)
830 0 : return handled;
831 11 : } else if (pkt->vp_type == VP_TYPE_IP6) {
832 11 : if (is_ipv6_nd_packet) {
833 10 : handled = vr_ipv6_nd_input(pkt, fmd);
834 : } else {
835 1 : handled = vr_l3_input(pkt, fmd);
836 : }
837 : }
838 :
839 28 : if (!handled) {
840 4 : pkt_push(pkt, pull_len);
841 4 : return vif_xconnect(vif, pkt, fmd);
842 : }
843 :
844 24 : return 0;
845 : }
846 :
847 : int
848 45 : vr_l3_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
849 : {
850 45 : struct vr_interface *vif = pkt->vp_if;
851 :
852 45 : if (pkt->vp_type == VP_TYPE_IP) {
853 44 : vr_ip_input(vif->vif_router, pkt, fmd);
854 44 : return 1;
855 1 : } else if (pkt->vp_type == VP_TYPE_IP6) {
856 1 : vr_ip6_input(vif->vif_router, pkt, fmd);
857 1 : return 1;
858 : }
859 0 : return 0;
860 : }
861 :
862 : /*
863 : * Function to remove vlan from ethernet header. As it modifies vr_packet
864 : * structure and not skb, one is expected to invoke vr_pset_data() to
865 : * modify the data pointer of skb.
866 : */
867 :
868 : int
869 0 : vr_untag_pkt(struct vr_packet *pkt)
870 : {
871 : struct vr_eth *eth;
872 : unsigned char *new_eth;
873 :
874 0 : eth = (struct vr_eth *)pkt_data(pkt);
875 0 : if (eth->eth_proto != htons(VR_ETH_PROTO_VLAN))
876 0 : return 0;
877 :
878 0 : new_eth = pkt_pull(pkt, VR_VLAN_HLEN);
879 0 : if (!new_eth)
880 0 : return -1;
881 :
882 0 : memmove(new_eth, eth, (2 * VR_ETHER_ALEN));
883 0 : return 0;
884 : }
885 :
886 : /*
887 : * Function to add vlan tag to ethernet header. As it modifies vr_packet
888 : * structure and not skb, one is expected to invoke vr_pset_data() to
889 : * modify the data pointer of skb
890 : */
891 : int
892 0 : vr_tag_pkt(struct vr_packet **pkt, unsigned short vlan_id, bool force_tag)
893 : {
894 0 : uint8_t priority = 0;
895 : struct vr_packet *tmp_pkt;
896 : struct vr_eth *new_eth, *eth;
897 : unsigned short *vlan_tag;
898 :
899 0 : eth = (struct vr_eth *)pkt_data(*pkt);
900 0 : if (!force_tag) {
901 0 : if (eth->eth_proto == htons(VR_ETH_PROTO_VLAN))
902 0 : return 0;
903 : }
904 :
905 0 : if (pkt_head_space(*pkt) < VR_VLAN_HLEN) {
906 0 : tmp_pkt = vr_pexpand_head(*pkt, VR_VLAN_HLEN - pkt_head_space(*pkt));
907 0 : if (!tmp_pkt) {
908 0 : return -1;
909 : }
910 0 : *pkt = tmp_pkt;
911 : }
912 :
913 0 : new_eth = (struct vr_eth *)pkt_push(*pkt, VR_VLAN_HLEN);
914 0 : if (!new_eth)
915 0 : return -1;
916 :
917 0 : memmove(new_eth, eth, (2 * VR_ETHER_ALEN));
918 0 : new_eth->eth_proto = htons(VR_ETH_PROTO_VLAN);
919 0 : vlan_tag = (unsigned short *)(new_eth + 1);
920 0 : if ((*pkt)->vp_priority != VP_PRIORITY_INVALID)
921 0 : priority = (*pkt)->vp_priority;
922 :
923 0 : *vlan_tag = htons((priority << VR_VLAN_PRIORITY_SHIFT) | vlan_id);
924 :
925 0 : return 0;
926 : }
927 :
928 : void
929 0 : vr_vlan_set_priority(struct vr_packet *pkt)
930 : {
931 : struct vr_eth *eth;
932 : struct vr_vlan_hdr *vlan;
933 :
934 0 : eth = (struct vr_eth *)pkt_data(pkt);
935 0 : if (eth->eth_proto == htons(VR_ETH_PROTO_VLAN)) {
936 0 : vlan = (struct vr_vlan_hdr *)(eth + 1);
937 0 : if (pkt->vp_priority != VP_PRIORITY_INVALID) {
938 0 : vlan->vlan_tag |=
939 0 : htons((pkt->vp_priority << VR_VLAN_PRIORITY_SHIFT));
940 : }
941 : }
942 :
943 0 : return;
944 : }
945 :
946 : int
947 4 : vr_gro_input(struct vr_packet *pkt, struct vr_nexthop *nh)
948 : {
949 4 : unsigned short push_len = 0;
950 4 : int handled = 1;
951 : struct vr_gro *gro;
952 :
953 4 : if (!vr_gro_process) {
954 0 : handled = 0;
955 0 : goto not_handled;
956 : }
957 :
958 4 : gro = (struct vr_gro *)pkt_push(pkt, sizeof(*gro));
959 4 : if (!gro) {
960 0 : handled = 0;
961 0 : goto not_handled;
962 : }
963 4 : push_len += sizeof(*gro);
964 :
965 4 : gro->vg_vif_id = pkt->vp_if->vif_idx;
966 4 : gro->pad = 0;
967 4 : gro->vg_nh_id = nh->nh_id;
968 :
969 4 : handled = vr_gro_process(pkt, nh->nh_dev, (nh->nh_family == AF_BRIDGE));
970 4 : not_handled:
971 4 : if (!handled) {
972 4 : pkt_pull(pkt, push_len);
973 : }
974 :
975 4 : return handled;
976 : }
977 :
978 : int
979 0 : __vr_pbb_decode(struct vr_eth *eth, int len, struct vr_forwarding_md *fmd)
980 : {
981 0 : int pbb_size = sizeof(struct vr_eth) + sizeof(struct vr_pbb_itag);
982 :
983 0 : if (!eth || !fmd || (len < pbb_size))
984 0 : return -1;
985 :
986 0 : if (ntohs(eth->eth_proto) != VR_ETH_PROTO_PBB)
987 0 : return -1;
988 :
989 : /* Copy the PBB mac addresses to fmd */
990 0 : VR_MAC_COPY(fmd->fmd_smac, eth->eth_smac);
991 0 : VR_MAC_COPY(fmd->fmd_dmac, eth->eth_dmac);
992 :
993 0 : return pbb_size;
994 : }
995 :
996 : int
997 0 : vr_pbb_decode(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
998 : {
999 0 : int pbb_size, decode_error = 1;
1000 :
1001 0 : pbb_size = __vr_pbb_decode((struct vr_eth *)pkt_data(pkt),
1002 0 : pkt_head_len(pkt), fmd);
1003 0 : if (pbb_size <= 0) {
1004 0 : PKT_LOG(VP_DROP_INVALID_PACKET, pkt, 0, VR_DATAPATH_C, __LINE__);
1005 0 : vr_pfree(pkt, VP_DROP_INVALID_PACKET);
1006 0 : return decode_error;
1007 : }
1008 :
1009 0 : if (!pkt_pull(pkt, pbb_size)) {
1010 0 : PKT_LOG(VP_DROP_PULL, pkt, 0, VR_DATAPATH_C, __LINE__);
1011 0 : vr_pfree(pkt, VP_DROP_PULL);
1012 0 : return decode_error;
1013 : }
1014 :
1015 : /* Get the inner ether type and header pointers */
1016 0 : if (vr_pkt_type(pkt, 0, fmd) < 0) {
1017 0 : PKT_LOG(VP_DROP_INVALID_PACKET, pkt, 0, VR_DATAPATH_C, __LINE__);
1018 0 : vr_pfree(pkt, VP_DROP_INVALID_PACKET);
1019 0 : return decode_error;
1020 : }
1021 :
1022 0 : return !decode_error;
1023 : }
|