Line data Source code
1 : /*
2 : * vr_mpls.c -- mpls handling of packets
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : */
6 : #include <vr_os.h>
7 : #include <vr_types.h>
8 : #include <vr_packet.h>
9 : #include "vr_interface.h"
10 : #include "vr_message.h"
11 : #include "vr_sandesh.h"
12 : #include "vr_mpls.h"
13 : #include "vr_bridge.h"
14 : #include "vr_datapath.h"
15 : #include "vr_btable.h"
16 : #include "vr_offloads_dp.h"
17 :
18 : unsigned int vr_mpls_labels = VR_DEF_LABELS;
19 :
20 : struct vr_nexthop *
21 271387 : __vrouter_get_label(struct vrouter *router, unsigned int label)
22 : {
23 271387 : if (!router || label >= router->vr_max_labels)
24 0 : return NULL;
25 :
26 271387 : return *(struct vr_nexthop **)vr_btable_get(router->vr_ilm, label);
27 : }
28 :
29 : static struct vr_nexthop *
30 1 : vrouter_get_label(unsigned int rid, unsigned int label)
31 : {
32 1 : struct vrouter *router = vrouter_get(rid);
33 :
34 1 : return __vrouter_get_label(router, label);
35 : }
36 :
37 : static int
38 27 : __vrouter_set_label(struct vrouter *router, unsigned int label,
39 : struct vr_nexthop *nh)
40 : {
41 : struct vr_nexthop **nh_p;
42 :
43 27 : nh_p = (struct vr_nexthop **)vr_btable_get(router->vr_ilm, label);
44 27 : if (!nh_p)
45 0 : return -EINVAL;
46 :
47 27 : *nh_p = nh;
48 :
49 27 : return 0;
50 : }
51 :
52 : static int
53 18 : __vr_mpls_del(struct vrouter *router, unsigned int label)
54 : {
55 : struct vr_nexthop *nh;
56 :
57 : /* hardware packet filtering (Flow Director) support */
58 18 : nh = __vrouter_get_label(router, label);
59 18 : if (nh) {
60 9 : if (vrouter_host->hos_del_mpls
61 9 : && nh->nh_type == NH_ENCAP && !(nh->nh_flags & NH_FLAG_MCAST))
62 9 : vrouter_host->hos_del_mpls(router, label);
63 :
64 9 : vrouter_put_nexthop(nh);
65 : }
66 :
67 18 : return __vrouter_set_label(router, label, NULL);
68 : }
69 :
70 : static int
71 9 : vr_mpls_del(vr_mpls_req *req)
72 : {
73 9 : int ret = 0;
74 :
75 : struct vrouter *router;
76 :
77 9 : router = vrouter_get(req->mr_rid);
78 9 : if (!router) {
79 0 : ret = -EINVAL;
80 0 : goto generate_resp;
81 : }
82 :
83 9 : if ((unsigned int)req->mr_label >= router->vr_max_labels) {
84 0 : ret = -EINVAL;
85 0 : goto generate_resp;
86 : }
87 :
88 : /* notify hw offload of change, if enabled */
89 9 : vr_offload_mpls_del(req->mr_label);
90 :
91 9 : ret = __vr_mpls_del(router, req->mr_label);
92 :
93 9 : generate_resp:
94 9 : vr_send_response(ret);
95 :
96 9 : return ret;
97 : }
98 :
99 : int
100 9 : vr_mpls_add(vr_mpls_req *req)
101 : {
102 : struct vrouter *router;
103 : struct vr_nexthop *nh;
104 9 : int ret = 0;
105 :
106 9 : router = vrouter_get(req->mr_rid);
107 9 : if (!router) {
108 0 : ret = -EINVAL;
109 0 : goto generate_resp;
110 : }
111 :
112 9 : if ((unsigned int)req->mr_label >= router->vr_max_labels) {
113 0 : ret = -EINVAL;
114 0 : goto generate_resp;
115 : }
116 :
117 9 : ret = __vr_mpls_del(router, req->mr_label);
118 9 : if (ret)
119 0 : goto generate_resp;
120 :
121 9 : nh = vrouter_get_nexthop(req->mr_rid, req->mr_nhid);
122 9 : if (!nh) {
123 0 : ret = -EINVAL;
124 0 : goto generate_resp;
125 : }
126 :
127 9 : ret = __vrouter_set_label(router, req->mr_label, nh);
128 9 : if (ret) {
129 0 : vrouter_put_nexthop(nh);
130 0 : goto generate_resp;
131 : }
132 :
133 : /* hardware packet filtering (Flow Director) support */
134 9 : if (vrouter_host->hos_add_mpls
135 9 : && nh->nh_type == NH_ENCAP && !(nh->nh_flags & NH_FLAG_MCAST))
136 9 : vrouter_host->hos_add_mpls(router, req->mr_label);
137 :
138 : /* notify hw offload of change, if enabled */
139 9 : if (!ret) {
140 9 : ret = vr_offload_mpls_add(nh, req->mr_label);
141 9 : if (ret)
142 0 : __vr_mpls_del(router, req->mr_label);
143 : }
144 :
145 9 : generate_resp:
146 9 : vr_send_response(ret);
147 :
148 9 : return ret;
149 : }
150 :
151 : static void
152 1 : vr_mpls_make_req(vr_mpls_req *req, struct vr_nexthop *nh,
153 : unsigned int label)
154 : {
155 1 : req->mr_rid = 0;
156 1 : req->mr_nhid = nh->nh_id;
157 1 : req->mr_label = label;
158 :
159 : /* Debug comparison to check if matching entry is programmed on NIC */
160 1 : vr_offload_mpls_get(req);
161 :
162 1 : return;
163 : }
164 :
165 : int
166 0 : vr_mpls_dump(vr_mpls_req *r)
167 : {
168 0 : int ret = 0;
169 : unsigned int i;
170 : struct vr_nexthop *nh;
171 0 : struct vrouter *router = vrouter_get(r->mr_rid);
172 0 : struct vr_message_dumper *dumper = NULL;
173 : vr_mpls_req req;
174 :
175 0 : if (!router && (ret = -ENODEV))
176 0 : goto generate_response;
177 :
178 0 : if ((unsigned int)(r->mr_marker) + 1 >= router->vr_max_labels)
179 0 : goto generate_response;
180 :
181 0 : dumper = vr_message_dump_init(r);
182 0 : if (!dumper && (ret = -ENOMEM))
183 0 : goto generate_response;
184 :
185 0 : for (i = (unsigned int)(r->mr_marker + 1);
186 0 : i < router->vr_max_labels; i++) {
187 0 : nh = __vrouter_get_label(router, i);
188 0 : if (nh) {
189 0 : vr_mpls_make_req(&req, nh, i);
190 0 : ret = vr_message_dump_object(dumper, VR_MPLS_OBJECT_ID, &req);
191 0 : if (ret <= 0)
192 0 : break;
193 : }
194 : }
195 :
196 0 : generate_response:
197 0 : vr_message_dump_exit(dumper, ret);
198 :
199 0 : return 0;
200 : }
201 :
202 : int
203 1 : vr_mpls_get(vr_mpls_req *req)
204 : {
205 1 : int ret = 0;
206 1 : struct vr_nexthop *nh = NULL;
207 : struct vrouter *router;
208 :
209 1 : router = vrouter_get(req->mr_rid);
210 1 : if (!router) {
211 0 : ret = -ENODEV;
212 0 : goto generate_response;
213 : }
214 :
215 1 : if (((unsigned int)req->mr_label >= router->vr_max_labels)) {
216 0 : ret = -EINVAL;
217 0 : goto generate_response;
218 : }
219 :
220 1 : nh = vrouter_get_label(req->mr_rid, req->mr_label);
221 1 : if (!nh) {
222 0 : ret = -ENOENT;
223 0 : goto generate_response;
224 : }
225 :
226 1 : vr_mpls_make_req(req, nh, req->mr_label);
227 :
228 1 : generate_response:
229 1 : if (ret)
230 0 : req = NULL;
231 :
232 1 : vr_message_response(VR_MPLS_OBJECT_ID, req, ret, false);
233 :
234 1 : return 0;
235 : }
236 :
237 : void
238 19 : vr_mpls_req_process(void *s_req)
239 : {
240 19 : vr_mpls_req *req = (vr_mpls_req *)s_req;
241 :
242 19 : switch (req->h_op) {
243 9 : case SANDESH_OP_ADD:
244 9 : vr_mpls_add(req);
245 9 : break;
246 :
247 1 : case SANDESH_OP_GET:
248 1 : vr_mpls_get(req);
249 1 : break;
250 :
251 0 : case SANDESH_OP_DUMP:
252 0 : vr_mpls_dump(req);
253 0 : break;
254 :
255 9 : case SANDESH_OP_DEL:
256 9 : vr_mpls_del(req);
257 9 : break;
258 :
259 0 : default:
260 0 : break;
261 : }
262 19 : }
263 :
264 : int
265 0 : vr_mpls_tunnel_type(unsigned int label, unsigned int control_data, unsigned
266 : short *reason)
267 : {
268 : struct vr_nexthop *nh;
269 0 : struct vrouter *router = vrouter_get(0);
270 : unsigned short res;
271 :
272 0 : if (!router) {
273 0 : res = VP_DROP_MISC;
274 0 : PKT_LOG(res, 0, 0, VR_MPLS_C, __LINE__);
275 0 : goto fail;
276 : }
277 :
278 0 : label >>= VR_MPLS_LABEL_SHIFT;
279 0 : if (label >= router->vr_max_labels) {
280 0 : res = VP_DROP_INVALID_LABEL;
281 0 : PKT_LOG(res, 0, 0, VR_MPLS_C, __LINE__);
282 0 : goto fail;
283 : }
284 :
285 0 : nh = __vrouter_get_label(router, label);
286 0 : if(!nh) {
287 0 : res = VP_DROP_INVALID_LABEL;
288 0 : PKT_LOG(res, 0, 0, VR_MPLS_C, __LINE__);
289 0 : goto fail;
290 : }
291 :
292 0 : switch(nh->nh_family) {
293 0 : case AF_INET:
294 0 : return PKT_MPLS_TUNNEL_L3;
295 0 : case AF_BRIDGE:
296 0 : if ((nh->nh_type == NH_COMPOSITE) && (label >= VR_MAX_UCAST_LABELS))
297 0 : return PKT_MPLS_TUNNEL_L2_MCAST;
298 :
299 0 : if (nh->nh_flags & NH_FLAG_L2_CONTROL_DATA)
300 0 : return PKT_MPLS_TUNNEL_L2_CONTROL_DATA;
301 :
302 0 : return PKT_MPLS_TUNNEL_L2_UCAST;
303 :
304 0 : default:
305 0 : res = VP_DROP_INVALID_NH;
306 0 : PKT_LOG(res, 0, 0, VR_MPLS_C, __LINE__);
307 : }
308 :
309 0 : fail:
310 0 : if (reason)
311 0 : *reason = res;
312 0 : return -1;
313 : }
314 :
315 : int
316 7 : vr_mpls_input(struct vrouter *router, struct vr_packet *pkt,
317 : struct vr_forwarding_md *fmd)
318 : {
319 7 : int ttl, l2_offset = 0, pull_len = 0;
320 : unsigned int label;
321 : unsigned short drop_reason;
322 :
323 : struct vr_nexthop *nh;
324 : struct vr_ip *ip;
325 : struct vr_forwarding_md c_fmd;
326 :
327 7 : if (!fmd) {
328 0 : vr_init_forwarding_md(&c_fmd);
329 0 : fmd = &c_fmd;
330 : }
331 :
332 7 : label = ntohl(*(unsigned int *)pkt_data(pkt));
333 : /* if outer label is 0xFFFFF, iterpret it as no label
334 : * and parse packet to get inner label
335 : */
336 7 : if (!(label & VR_MPLS_LABEL_STACK_BIT_MASK)
337 0 : && ((label >> VR_MPLS_LABEL_SHIFT) ==
338 : VR_MPLS_LABEL_MASK)) {
339 : /* drop the top Stack label */
340 0 : if (!pkt_pull(pkt, VR_MPLS_HDR_LEN)) {
341 0 : drop_reason = VP_DROP_PULL;
342 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
343 0 : goto dropit;
344 : }
345 0 : label = ntohl(*(unsigned int *)pkt_data(pkt));
346 : }
347 7 : ttl = label & 0xFF;
348 7 : label >>= VR_MPLS_LABEL_SHIFT;
349 7 : if (label >= router->vr_max_labels) {
350 0 : drop_reason = VP_DROP_INVALID_LABEL;
351 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
352 0 : goto dropit;
353 : }
354 :
355 7 : if (--ttl <= 0) {
356 0 : drop_reason = VP_DROP_TTL_EXCEEDED;
357 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
358 0 : goto dropit;
359 : }
360 :
361 7 : ip = (struct vr_ip *)pkt_network_header(pkt);
362 7 : fmd->fmd_outer_src_ip = ip->ip_saddr;
363 7 : vr_fmd_set_label(fmd, label, VR_LABEL_TYPE_MPLS);
364 :
365 : /* Store the TTL in packet. Will be used for multicast replication */
366 7 : pkt->vp_ttl = ttl;
367 :
368 : /* drop the TOStack label */
369 7 : if (!pkt_pull(pkt, VR_MPLS_HDR_LEN)) {
370 0 : drop_reason = VP_DROP_PULL;
371 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
372 0 : goto dropit;
373 : }
374 :
375 7 : if (!fmd->fmd_fe) {
376 7 : nh = __vrouter_get_label(router, label);
377 7 : if (!nh) {
378 0 : drop_reason = VP_DROP_INVALID_LABEL;
379 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
380 0 : goto dropit;
381 : }
382 : } else
383 0 : nh = pkt->vp_nh;
384 :
385 : /*
386 : * Mark it for GRO. Diag, L2 and multicast nexthops unmark if
387 : * required
388 : */
389 7 : if (vr_perfr) {
390 7 : vr_pkt_set_gro(pkt);
391 : }
392 :
393 : /* Reset the flags which get defined below */
394 7 : pkt->vp_flags &= ~VP_FLAG_MULTICAST;
395 7 : fmd->fmd_vlan = VLAN_ID_INVALID;
396 :
397 7 : if (nh->nh_family == AF_INET) {
398 4 : ip = (struct vr_ip *)pkt_data(pkt);
399 4 : if (vr_ip_is_ip4(ip)) {
400 2 : pkt->vp_type = VP_TYPE_IP;
401 2 : } else if (vr_ip_is_ip6(ip)) {
402 2 : pkt->vp_type = VP_TYPE_IP6;
403 : } else {
404 0 : drop_reason = VP_DROP_INVALID_PROTOCOL;
405 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
406 0 : goto dropit;
407 : }
408 :
409 4 : pkt_set_network_header(pkt, pkt->vp_data);
410 4 : pkt_set_inner_network_header(pkt, pkt->vp_data);
411 :
412 3 : } else if (nh->nh_family == AF_BRIDGE) {
413 :
414 3 : if (nh->nh_flags & NH_FLAG_L2_CONTROL_DATA) {
415 0 : vr_fmd_update_l2_control_data(fmd, true);
416 0 : pull_len = VR_L2_CTRL_DATA_LEN;
417 : }
418 :
419 3 : if ((nh->nh_type == NH_COMPOSITE) && (label >= VR_MAX_UCAST_LABELS)) {
420 0 : l2_offset = VR_VXLAN_HDR_LEN;
421 0 : pull_len = VR_L2_CTRL_DATA_LEN;
422 : }
423 :
424 3 : if (pull_len) {
425 0 : if (*(unsigned int *)pkt_data(pkt) != VR_L2_CTRL_DATA) {
426 0 : drop_reason = VP_DROP_INVALID_PACKET;
427 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
428 0 : goto dropit;
429 : }
430 :
431 0 : if (!pkt_pull(pkt, pull_len)) {
432 0 : drop_reason = VP_DROP_PULL;
433 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
434 0 : goto dropit;
435 : }
436 : }
437 :
438 3 : if (vr_pkt_type(pkt, l2_offset, fmd) < 0) {
439 0 : drop_reason = VP_DROP_INVALID_PACKET;
440 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
441 0 : goto dropit;
442 : }
443 : } else {
444 0 : drop_reason = VP_DROP_INVALID_NH;
445 0 : PKT_LOG(drop_reason, pkt, 0, VR_MPLS_C, __LINE__);
446 0 : goto dropit;
447 : }
448 :
449 : /*
450 : * We are typically looking at interface nexthops, and hence we will
451 : * hit the vrf of the destination device. But, labels can also point
452 : * to composite nexthops (ECMP being case in point), in which case we
453 : * will take the vrf from the nexthop. When everything else fails, we
454 : * will forward the packet in the vrf in which it came i.e fabric
455 : */
456 7 : if (nh->nh_vrf >= 0)
457 7 : fmd->fmd_dvrf = nh->nh_vrf;
458 0 : else if (nh->nh_dev)
459 0 : fmd->fmd_dvrf = nh->nh_dev->vif_vrf;
460 : else
461 0 : fmd->fmd_dvrf = pkt->vp_if->vif_vrf;
462 :
463 7 : nh_output(pkt, nh, fmd);
464 :
465 7 : return 0;
466 :
467 0 : dropit:
468 0 : vr_pfree(pkt, drop_reason);
469 0 : return 0;
470 : }
471 :
472 : void
473 53 : vr_mpls_exit(struct vrouter *router, bool soft_reset)
474 : {
475 : unsigned int i;
476 : struct vr_nexthop *nh;
477 :
478 53 : if (!router->vr_max_labels || !router->vr_ilm)
479 0 : return;
480 :
481 271413 : for (i = 0; i < router->vr_max_labels; i++) {
482 271360 : nh = __vrouter_get_label(router, i);
483 271360 : if (nh) {
484 0 : vrouter_put_nexthop(nh);
485 0 : __vrouter_set_label(router, i, NULL);
486 : }
487 : }
488 :
489 53 : if (soft_reset == false) {
490 53 : vr_btable_free(router->vr_ilm);
491 53 : router->vr_ilm = NULL;
492 53 : router->vr_max_labels = 0;
493 : }
494 :
495 53 : return;
496 : }
497 :
498 : int
499 53 : vr_mpls_init(struct vrouter *router)
500 : {
501 : int ilm_memory;
502 :
503 53 : if (!router->vr_ilm) {
504 53 : router->vr_max_labels = vr_mpls_labels;
505 53 : ilm_memory = sizeof(struct vr_nexthop *) * router->vr_max_labels;
506 53 : router->vr_ilm = vr_btable_alloc(router->vr_max_labels,
507 : sizeof(struct vr_nexthop *));
508 53 : if (!router->vr_ilm)
509 0 : return vr_module_error(-ENOMEM, __FUNCTION__,
510 : __LINE__, ilm_memory);
511 : }
512 :
513 53 : return 0;
514 : }
|