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