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