Line data Source code
1 : /*
2 : * nh.c
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : * Copyright Contributors to the OpenSDN project
6 : */
7 :
8 : #include <stdio.h>
9 : #include <stdlib.h>
10 : #include <unistd.h>
11 : #include <string.h>
12 : #include <errno.h>
13 : #include <stdlib.h>
14 : #include <stdbool.h>
15 : #include <getopt.h>
16 :
17 : #include <sys/types.h>
18 : #include <sys/socket.h>
19 :
20 : #include <net/if.h>
21 :
22 : #if defined(__linux__)
23 : #include <netinet/ether.h>
24 : #endif
25 :
26 : #include "vr_types.h"
27 : #include "vr_nexthop.h"
28 : #include "vr_os.h"
29 : #include "nl_util.h"
30 : #include "ini_parser.h"
31 :
32 : static int8_t src_mac[3][6], dst_mac[3][6], l3_vxlan_mac[6];
33 : static uint16_t sport, dport;
34 : static uint32_t nh_id, if_id[3] = {-1, -1, -1}, vrf_id, flags;
35 : static int nh_set, command, type, dump_marker = -1;
36 : static int family = AF_INET, count = 0;
37 :
38 : static bool dump_pending = false;
39 : static int comp_nh[32], lbl[32];
40 : static int comp_nh_ind = 0, lbl_ind = 0;
41 :
42 : static struct in_addr sip, dip;
43 : static struct nl_client *cl;
44 :
45 : static int
46 : vr_nh_op(struct nl_client *cl, int command, int type, uint32_t nh_id,
47 : uint32_t *if_id, uint32_t vrf_id, int8_t dst[][6], int8_t src[][6],
48 : struct in_addr sip, struct in_addr dip, uint32_t flags);
49 :
50 : char *
51 4 : nh_type(uint32_t type)
52 : {
53 4 : switch (type) {
54 0 : case NH_DEAD:
55 0 : return "Dead";
56 :
57 0 : case NH_RCV:
58 0 : return "Receive";
59 :
60 0 : case NH_L2_RCV:
61 0 : return "L2 Receive";
62 :
63 0 : case NH_ENCAP:
64 0 : return "Encap";
65 :
66 4 : case NH_TUNNEL:
67 4 : return "Tunnel";
68 :
69 0 : case NH_DISCARD:
70 0 : return "Drop";
71 :
72 0 : case NH_RESOLVE:
73 0 : return "Resolve";
74 :
75 0 : case NH_COMPOSITE:
76 0 : return "Composite";
77 :
78 0 : case NH_VRF_TRANSLATE:
79 0 : return "Vrf_Translate";
80 :
81 0 : default:
82 0 : return "Invalid";
83 : }
84 :
85 : return NULL;
86 : }
87 :
88 : char *
89 0 : nh_ecmp_config_hash_str(uint8_t hash, char *ptr)
90 : {
91 : int i;
92 :
93 0 : strcpy(ptr,"");
94 0 : hash = hash & ((1 << NH_ECMP_CONFIG_HASH_BITS) - 1);
95 0 : for (i = 0; i < NH_ECMP_CONFIG_HASH_BITS; i++) {
96 0 : switch (hash & (1 << i)) {
97 0 : case 0:
98 0 : break;
99 0 : case NH_ECMP_CONFIG_HASH_PROTO:
100 0 : strcat(ptr, "Proto,");
101 0 : break;
102 0 : case NH_ECMP_CONFIG_HASH_SRC_IP:
103 0 : strcat(ptr, "SrcIP,");
104 0 : break;
105 0 : case NH_ECMP_CONFIG_HASH_SRC_PORT:
106 0 : strcat(ptr, "SrcPort,");
107 0 : break;
108 0 : case NH_ECMP_CONFIG_HASH_DST_IP:
109 0 : strcat(ptr, "DstIp,");
110 0 : break;
111 0 : case NH_ECMP_CONFIG_HASH_DST_PORT:
112 0 : strcat(ptr, "DstPort");
113 0 : break;
114 0 : default:
115 0 : strcat(ptr, "Invalid,");
116 0 : break;
117 : }
118 : }
119 :
120 0 : return ptr;
121 : }
122 :
123 : char *
124 4 : nh_flags(uint32_t flags, uint8_t type, char *ptr)
125 : {
126 : int i;
127 : uint32_t mask;
128 :
129 4 : if (!flags) {
130 0 : strcpy(ptr, "None");
131 0 : return ptr;
132 : }
133 :
134 :
135 4 : strcpy(ptr,"");
136 132 : for (i = 0, mask = 1; (i < 32); i++, mask = mask << 1) {
137 128 : switch(flags & mask) {
138 4 : case NH_FLAG_VALID:
139 4 : strcat(ptr, "Valid, ");
140 4 : break;
141 :
142 0 : case NH_FLAG_POLICY_ENABLED:
143 0 : strcat(ptr, "Policy, ");
144 0 : break;
145 :
146 0 : case NH_FLAG_RELAXED_POLICY:
147 0 : strcat(ptr, "Policy(R), ");
148 0 : break;
149 :
150 0 : case NH_FLAG_FLOW_LOOKUP:
151 0 : strcat(ptr, "Flow Lookup, ");
152 0 : break;
153 :
154 0 : case NH_FLAG_TUNNEL_GRE:
155 0 : if (type == NH_TUNNEL) {
156 0 : if (flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
157 0 : strcat(ptr, "MPLSo");
158 : }
159 0 : strcat(ptr, "MPLSoGRE, ");
160 : }
161 0 : break;
162 :
163 4 : case NH_FLAG_TUNNEL_UDP_MPLS:
164 4 : if (type == NH_TUNNEL) {
165 4 : if (flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
166 0 : strcat(ptr, "MPLSo");
167 : }
168 4 : strcat(ptr, "MPLSoUDP, ");
169 : }
170 4 : break;
171 :
172 0 : case NH_FLAG_TUNNEL_UDP:
173 0 : if (type == NH_TUNNEL)
174 0 : strcat(ptr, "Udp, ");
175 0 : break;
176 :
177 0 : case NH_FLAG_COMPOSITE_ECMP:
178 0 : if (type == NH_COMPOSITE)
179 0 : strcat(ptr, "Ecmp, ");
180 0 : break;
181 :
182 0 : case NH_FLAG_COMPOSITE_FABRIC:
183 0 : if (type == NH_COMPOSITE)
184 0 : strcat(ptr, "Fabric, ");
185 0 : break;
186 :
187 0 : case NH_FLAG_COMPOSITE_EVPN:
188 0 : if (type == NH_COMPOSITE)
189 0 : strcat(ptr, "Evpn, ");
190 0 : break;
191 0 : case NH_FLAG_COMPOSITE_TOR:
192 0 : if (type == NH_COMPOSITE)
193 0 : strcat(ptr, "Tor, ");
194 0 : break;
195 :
196 0 : case NH_FLAG_COMPOSITE_ENCAP:
197 0 : if (type == NH_COMPOSITE)
198 0 : strcat(ptr, "Encap, ");
199 0 : break;
200 :
201 0 : case NH_FLAG_MCAST:
202 0 : strcat(ptr, "Multicast, ");
203 0 : break;
204 :
205 0 : case NH_FLAG_ROUTE_LOOKUP:
206 0 : strcat(ptr, "RouteLookup, ");
207 0 : break;
208 :
209 0 : case NH_FLAG_L3_VXLAN:
210 0 : strcat(ptr, "l3_vxlan, ");
211 0 : break;
212 :
213 0 : case NH_FLAG_TUNNEL_VXLAN:
214 0 : strcat(ptr, "Vxlan, ");
215 0 : break;
216 :
217 0 : case NH_FLAG_UNKNOWN_UC_FLOOD:
218 0 : strcat(ptr, "Unicast Flood, ");
219 0 : break;
220 :
221 0 : case NH_FLAG_TUNNEL_SIP_COPY:
222 0 : strcat(ptr, "Copy SIP, ");
223 0 : break;
224 :
225 0 : case NH_FLAG_TUNNEL_PBB:
226 0 : strcat(ptr, "Pbb, ");
227 0 : break;
228 :
229 0 : case NH_FLAG_INDIRECT:
230 0 : strcat(ptr, "Indirect, ");
231 0 : break;
232 :
233 4 : case NH_FLAG_ETREE_ROOT:
234 4 : strcat(ptr, "Etree Root, ");
235 4 : break;
236 :
237 0 : case NH_FLAG_MAC_LEARN:
238 0 : strcat(ptr, "Mac Learn, ");
239 0 : break;
240 :
241 0 : case NH_FLAG_L2_CONTROL_DATA:
242 0 : strcat(ptr, "Evpn Control Word, ");
243 0 : break;
244 :
245 0 : case NH_FLAG_CRYPT_TRAFFIC:
246 0 : strcat(ptr, "Encrypt Traffic, ");
247 0 : break;
248 :
249 4 : case NH_FLAG_TUNNEL_UNDERLAY_ECMP:
250 4 : strcat(ptr, "Underlay Ecmp, ");
251 4 : break;
252 : }
253 : }
254 :
255 4 : return ptr;
256 : }
257 :
258 : static void
259 20 : nh_print_newline_header(void)
260 : {
261 20 : printf("\n%14c", ' ');
262 20 : return;
263 : }
264 :
265 : static void
266 4 : nexthop_req_process(void *s_req)
267 : {
268 4 : unsigned int i, j, printed = 0;
269 : struct in_addr a;
270 : char flags_mem[500];
271 : char fam[100];
272 4 : char in6_dst[INET6_ADDRSTRLEN] = { 0 };
273 :
274 4 : vr_nexthop_req *req = (vr_nexthop_req *)(s_req);
275 :
276 4 : if (req->nhr_family == AF_INET)
277 4 : strcpy(fam, "AF_INET");
278 0 : else if (req->nhr_family == AF_INET6)
279 0 : strcpy(fam, "AF_INET6");
280 0 : else if (req->nhr_family == AF_BRIDGE)
281 0 : strcpy(fam, "AF_BRIDGE");
282 0 : else if (req->nhr_family == AF_UNSPEC)
283 0 : strcpy(fam, "AF_UNSPEC");
284 : else
285 0 : strcpy(fam, "N/A");
286 :
287 4 : printf("Id:%-9d Type:%-13s Fmly:%8s Rid:%d Ref_cnt:%-10d Vrf:%d",
288 4 : req->nhr_id, nh_type(req->nhr_type), fam,
289 : req->nhr_rid, req->nhr_ref_cnt, req->nhr_vrf);
290 4 : nh_print_newline_header();
291 4 : printf("Flags:%s",
292 4 : nh_flags(req->nhr_flags, req->nhr_type, flags_mem));
293 :
294 4 : if ((req->nhr_flags & NH_FLAG_INDIRECT) && (req->nhr_nh_list_size)) {
295 0 : i = -1;
296 0 : if (req->nhr_label_list_size)
297 0 : i = req->nhr_label_list[0];
298 0 : nh_print_newline_header();
299 0 : printf("Direct NH(label): %d(%d)", req->nhr_nh_list[0], i);
300 : }
301 :
302 4 : if (req->nhr_type == NH_RCV) {
303 0 : nh_print_newline_header();
304 0 : printf("Oif:%d", req->nhr_encap_oif_id[0]);
305 4 : } else if (req->nhr_type == NH_ENCAP) {
306 0 : nh_print_newline_header();
307 0 : printf("EncapFmly:%04x Oif:%d Len:%d", req->nhr_encap_family,
308 0 : req->nhr_encap_oif_id[0], req->nhr_encap_size);
309 0 : nh_print_newline_header();
310 0 : printf("Encap Data: ");
311 0 : for (i = 0; i< req->nhr_encap_size; i++) {
312 0 : printf("%02x ", (unsigned char)req->nhr_encap[i]);
313 : }
314 4 : } else if (req->nhr_type == NH_TUNNEL) {
315 4 : nh_print_newline_header();
316 4 : if (!(req->nhr_flags & NH_FLAG_TUNNEL_PBB)) {
317 4 : if (req->nhr_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
318 16 : for (i = 0; i < req->nhr_encap_oif_id_size; i++) {
319 12 : printf("Oif:%d EncapValid:%d ",
320 12 : req->nhr_encap_oif_id[i], req->nhr_encap_valid[i]);
321 12 : if (req->nhr_encap_valid[i]) {
322 6 : printf("Len:%d Data:", req->nhr_encap_len);
323 90 : for (j = 0; j < req->nhr_encap_len; j++) {
324 84 : printf("%02x ",
325 84 : (unsigned char)req->nhr_encap[i*req->nhr_encap_len+j]);
326 : }
327 : } else
328 6 : printf("Len:0 Data:NULL");
329 12 : nh_print_newline_header();
330 : }
331 : } else {
332 0 : printf("Oif:%d Len:%d Data:",
333 0 : req->nhr_encap_oif_id[0], req->nhr_encap_size);
334 0 : for (i = 0; i< req->nhr_encap_size; i++) {
335 0 : printf("%02x ", (unsigned char)req->nhr_encap[i]);
336 : }
337 0 : nh_print_newline_header();
338 : }
339 : }
340 4 : if (!(req->nhr_flags & NH_FLAG_TUNNEL_PBB)) {
341 4 : if (req->nhr_family == AF_INET) {
342 4 : a.s_addr = req->nhr_tun_sip;
343 4 : printf("Sip:%s", inet_ntoa(a));
344 4 : a.s_addr = req->nhr_tun_dip;
345 4 : printf(" Dip:%s", inet_ntoa(a));
346 0 : } else if (req->nhr_family == AF_INET6) {
347 0 : printf("Sip: %s",
348 0 : inet_ntop(AF_INET6, (struct in6_addr *)req->nhr_tun_sip6,
349 : in6_dst, sizeof(in6_dst)));
350 0 : printf(" Dip: %s",
351 0 : inet_ntop(AF_INET6, (struct in6_addr *)req->nhr_tun_dip6,
352 : in6_dst, sizeof(in6_dst)));
353 : }
354 : }
355 :
356 4 : if (req->nhr_flags & NH_FLAG_TUNNEL_UDP) {
357 0 : nh_print_newline_header();
358 0 : printf("Sport:%d Dport:%d\n", ntohs(req->nhr_tun_sport),
359 0 : ntohs(req->nhr_tun_dport));
360 : }
361 :
362 4 : if (req->nhr_flags & NH_FLAG_L3_VXLAN)
363 0 : printf(" L3_Vxlan_Mac: "MAC_FORMAT,
364 0 : MAC_VALUE((uint8_t*)req->nhr_rw_dst_mac));
365 :
366 4 : if (req->nhr_flags & NH_FLAG_TUNNEL_PBB) {
367 0 : i = -1;
368 0 : if (req->nhr_label_list_size)
369 0 : i = req->nhr_label_list[0];
370 0 : printf("Bmac:"MAC_FORMAT " Label:%d",
371 0 : MAC_VALUE((uint8_t *)req->nhr_pbb_mac), i);
372 : }
373 4 : if(req->nhr_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
374 0 : printf(" Transport Label:%u", req->nhr_transport_label);
375 : }
376 4 : if (req->nhr_encap_crypt_oif_id != (int)-1 &&
377 4 : req->nhr_encap_crypt_oif_id != 0) {
378 0 : nh_print_newline_header();
379 0 : printf("CryptOif:%d\n", req->nhr_encap_crypt_oif_id);
380 : }
381 0 : } else if (req->nhr_type == NH_VRF_TRANSLATE) {
382 0 : nh_print_newline_header();
383 0 : printf("Vrf:%d", req->nhr_vrf);
384 0 : } else if (req->nhr_type == NH_COMPOSITE) {
385 0 : if (req->nhr_flags & NH_FLAG_COMPOSITE_ECMP) {
386 0 : if (req->nhr_ecmp_config_hash) {
387 0 : nh_print_newline_header();
388 0 : nh_ecmp_config_hash_str(req->nhr_ecmp_config_hash, flags_mem);
389 0 : printf("Valid Hash Key Parameters: %s", flags_mem);
390 : }
391 : }
392 0 : nh_print_newline_header();
393 0 : printf("Sub NH(label):");
394 0 : for (i = 0; i < req->nhr_nh_list_size; i++) {
395 0 : if (printed > 60) {
396 0 : nh_print_newline_header();
397 0 : printf("%14c", ' ');
398 0 : printed = 0;
399 : }
400 0 : printed += printf(" %d", req->nhr_nh_list[i]);
401 0 : if (req->nhr_label_list[i] >= 0)
402 0 : printed += printf("(%d)", req->nhr_label_list[i]);
403 : }
404 :
405 0 : if (req->nhr_nh_count &&
406 0 : (req->nhr_nh_count - req->nhr_nh_list_size)) {
407 0 : printf(" and %u more components...\n",
408 0 : req->nhr_nh_count - req->nhr_nh_list_size);
409 : }
410 : }
411 :
412 4 : if (command == SANDESH_OP_DUMP) {
413 0 : dump_marker = req->nhr_id;
414 : }
415 :
416 4 : printf("\n\n");
417 4 : if (command == SANDESH_OP_GET) {
418 4 : if (req->nhr_type == NH_COMPOSITE) {
419 0 : for (i = 0; i < req->nhr_nh_list_size; i++) {
420 : // Skip expanding sub-nh for -1 index
421 0 : if (req->nhr_nh_list[i] == -1)
422 0 : continue;
423 0 : vr_nh_op(cl, command, type, req->nhr_nh_list[i], if_id, vrf_id,
424 : dst_mac, src_mac, sip, dip, flags);
425 : }
426 : }
427 :
428 4 : if ((req->nhr_flags & NH_FLAG_INDIRECT) && (req->nhr_nh_list_size)) {
429 0 : vr_nh_op(cl, command, type, req->nhr_nh_list[0], if_id, vrf_id,
430 : dst_mac, src_mac, sip, dip, flags);
431 : }
432 : }
433 4 : }
434 :
435 : static void
436 4 : response_process(void *s)
437 : {
438 4 : vr_response_common_process((vr_response *)s, &dump_pending);
439 4 : return;
440 : }
441 :
442 : static void
443 4 : nh_fill_nl_callbacks()
444 : {
445 4 : nl_cb.vr_response_process = response_process;
446 4 : nl_cb.vr_nexthop_req_process = nexthop_req_process;
447 4 : }
448 :
449 : static int
450 4 : vr_nh_op(struct nl_client *cl, int command, int type, uint32_t nh_id,
451 : uint32_t *if_id, uint32_t vrf_id, int8_t dst[][6], int8_t src[][6],
452 : struct in_addr sip, struct in_addr dip, uint32_t flags)
453 : {
454 : int ret;
455 4 : bool dump = false;
456 :
457 4 : op_retry:
458 4 : switch (command) {
459 0 : case SANDESH_OP_ADD:
460 0 : if (flags & NH_FLAG_TUNNEL_PBB) {
461 0 : ret = vr_send_pbb_tunnel_add(cl, 0, nh_id, flags,
462 0 : vrf_id, dst[0], comp_nh[0], lbl[0]);
463 0 : } else if ((type == NH_ENCAP) || (type == NH_TUNNEL)) {
464 0 : ret = vr_send_nexthop_encap_tunnel_add(cl, 0, type, nh_id,
465 : flags, vrf_id, if_id, src, dst, sip, dip, sport, dport, l3_vxlan_mac, family, count);
466 0 : } else if (type == NH_COMPOSITE) {
467 0 : ret = vr_send_nexthop_composite_add(cl, 0, nh_id, flags, vrf_id,
468 : comp_nh_ind, comp_nh, lbl, family);
469 : } else {
470 0 : ret = vr_send_nexthop_add(cl, 0, type, nh_id, flags, vrf_id, if_id, family);
471 : }
472 :
473 0 : break;
474 :
475 0 : case SANDESH_OP_DEL:
476 0 : ret = vr_send_nexthop_delete(cl, 0, nh_id);
477 0 : break;
478 :
479 0 : case SANDESH_OP_DUMP:
480 0 : dump = true;
481 0 : ret = vr_send_nexthop_dump(cl, 0, dump_marker);
482 0 : break;
483 :
484 4 : case SANDESH_OP_GET:
485 4 : ret = vr_send_nexthop_get(cl, 0, nh_id);
486 4 : break;
487 :
488 0 : default:
489 0 : ret = -EINVAL;
490 : }
491 :
492 4 : if (ret < 0)
493 0 : return ret;
494 :
495 4 : ret = vr_recvmsg(cl, dump);
496 4 : if (ret <= 0)
497 0 : return ret;
498 :
499 4 : if (dump_pending)
500 0 : goto op_retry;
501 :
502 4 : return 0;
503 : }
504 :
505 : void
506 0 : cmd_usage()
507 : {
508 0 : printf("Usage: [--create <nhid> create nexthop\n"
509 : " [--delete <nhid> delete nexthop\n"
510 : " [--vrf <vrf_id> ]\n"
511 : " [--pol NH with policy]\n"
512 : " [--rpol NH with relaxed policy]\n"
513 : " [--l2 NH with family bridge]\n"
514 : " [--root NH is an Etree Root]\n"
515 : " [--rlkup Force Route Lookup]\n"
516 : " [--type <type> type of the tunnel 1 - rcv, 2 - encap \n"
517 : " 3 - tunnel, 4 - resolve, 5 - discard, 6 - Composite\n"
518 : " 7 - VRF Translate, 8 - L2 Rcv NH] \n"
519 : " [RCV_NH options]\n"
520 : " [--oif <if_id> out going interface index]\n"
521 : " [L2RCV_NH options]\n"
522 : " [--oif <if_id> out going interface index]\n"
523 : " [ENCAP_NH optionsi - default L3]\n"
524 : " [--mc multicast nh]\n"
525 : " [--smac <xx:xx:xx:xx:xx:xx> source mac ]\n"
526 : " [--dmac <xx:xx:xx:xx:xx:xx> destination mac ]\n"
527 : " [--oif = out going interface index]\n"
528 : " [TUNNEL_NH options - default Gre]\n"
529 : " [--pbb PBB tunnel options]\n"
530 : " [--cni <nh_id> direct nh member id]\n"
531 : " [--lbl <lbl> Evpn label for PBB tunnel]\n"
532 : " [--dmac <xx:xx:xx:xx:xx:xx> destination Bmac]\n"
533 : " [--ind indirect flag]\n"
534 : " [--oif <if_id1,if_id2,...> comma seperated list of out going interface indices(max 3 in case of L3 multihoming)]\n"
535 : " [--smac <xx:xx:xx:xx:xx:xx,xx:xx:xx:xx:xx:xx,...> comma seperated list of source mac(max 3 in case of L3 multihoming)]\n"
536 : " [--dmac <xx:xx:xx:xx:xx:xx,xx:xx:xx:xx:xx:xx,...> comma seperated list of destination mac(max 3 in case of L3 multihoming)]\n"
537 : " [--sip <x.x.x.x> source ip of tunnel] \n"
538 : " [--dip <x.x.x.x> destination ip of tunnel ]\n"
539 : " [--udp Udptunnel ]\n"
540 : " [--sport <port> source port of udp tunnel]\n"
541 : " [--dport <port> destination port of udp tunnel]\n"
542 : " [--vxlan Vxlan Tunnel]\n"
543 : " [--sport <port> source port of vxlan tunnel]\n"
544 : " [--dport <port> destination port of vxlan tunnel]\n"
545 : " [--l3_vxlan <xx:xx:xx:xx:xx:xx> Remote EVPN-5 vRouter mac]\n"
546 : " [RESOLVE_NH options]\n"
547 : " [DISCARD_NH options]\n"
548 : " [COMPOSITE_NH options]\n"
549 : " [--cni <nh_id> composite nexthop member id]\n"
550 : " [--cmc composite multicast nexhop]\n"
551 : " [--cfa composit fabric ]\n"
552 : " [--cen composit encap ]\n"
553 : " [--cevpn composit evpn ]\n"
554 : " [--lbl <lbl> label for composit fabric ]\n"
555 : " [--tor composit tor ]\n"
556 : " [--lbl <lbl> label for composit fabric ]\n"
557 : " [--ecmp composite ecmp nexthop]\n"
558 : " [VRF Translate options]\n"
559 : " [--vxlan Vxlan VRF Translation]\n"
560 : " [--uucf Unknown Unicast Flood]\n");
561 0 : exit(-EINVAL);
562 : }
563 :
564 : void
565 0 : usage()
566 : {
567 0 : printf("Usage: nh --list\n"
568 : " nh --get <nh_id>\n"
569 : " nh --help\n\n"
570 : "--list Lists All Nexthops\n"
571 : "--get <nh_id> Displays nexthop corresponding to <nh_id>\n"
572 : "--sock-dir <netlink sock dir>\n"
573 : "--help Displays this help message\n\n");
574 :
575 0 : exit(-EINVAL);
576 : }
577 :
578 : enum opt_index {
579 : OIF_OPT_IND,
580 : SMAC_OPT_IND,
581 : DMAC_OPT_IND,
582 : VRF_OPT_IND,
583 : TYPE_OPT_IND,
584 : SIP_OPT_IND,
585 : DIP_OPT_IND,
586 : POL_OPT_IND,
587 : RPOL_OPT_IND,
588 : L2_OPT_IND,
589 : SPORT_OPT_IND,
590 : DPORT_OPT_IND,
591 : L3_VXLAN_OPT_IND,
592 : UDP_OPT_IND,
593 : VXLAN_OPT_IND,
594 : CNI_OPT_IND,
595 : CMC_OPT_IND,
596 : CFA_OPT_IND,
597 : MC_OPT_IND,
598 : CEN_OPT_IND,
599 : CEVPN_OPT_IND,
600 : TOR_OPT_IND,
601 : RLKUP_OPT_IND,
602 : LBL_OPT_IND,
603 : UUCF_OPT_IND,
604 : LST_OPT_IND,
605 : GET_OPT_IND,
606 : CRT_OPT_IND,
607 : DEL_OPT_IND,
608 : CMD_OPT_IND,
609 : IND_OPT_IND,
610 : PBB_OPT_IND,
611 : ROOT_OPT_IND,
612 : ML_OPT_IND,
613 : HLP_OPT_IND,
614 : SOCK_DIR_OPT_IND,
615 : ECMP_OPT_IND,
616 : MAX_OPT_IND
617 : };
618 :
619 : static int opt[MAX_OPT_IND], zero_opt[MAX_OPT_IND];
620 :
621 : static bool
622 16 : opt_set(int ind)
623 : {
624 16 : if (ind < 0 || ind >= MAX_OPT_IND)
625 0 : return false;
626 :
627 16 : if (opt[ind]) {
628 8 : opt[ind] = 0;
629 8 : return true;
630 : }
631 :
632 8 : return false;
633 : }
634 :
635 : static struct option long_options[] = {
636 : [OIF_OPT_IND] = {"oif", required_argument, &opt[OIF_OPT_IND], 1},
637 : [SMAC_OPT_IND] = {"smac", required_argument, &opt[SMAC_OPT_IND], 1},
638 : [DMAC_OPT_IND] = {"dmac", required_argument, &opt[DMAC_OPT_IND], 1},
639 : [VRF_OPT_IND] = {"vrf", required_argument, &opt[VRF_OPT_IND], 1},
640 : [TYPE_OPT_IND] = {"type", required_argument, &opt[TYPE_OPT_IND], 1},
641 : [SIP_OPT_IND] = {"sip", required_argument, &opt[SIP_OPT_IND], 1},
642 : [DIP_OPT_IND] = {"dip", required_argument, &opt[DIP_OPT_IND], 1},
643 : [POL_OPT_IND] = {"pol", no_argument, &opt[POL_OPT_IND], 1},
644 : [RPOL_OPT_IND] = {"rpol", no_argument, &opt[RPOL_OPT_IND], 1},
645 : [L2_OPT_IND] = {"l2", no_argument, &opt[L2_OPT_IND], 1},
646 : [SPORT_OPT_IND] = {"sport", required_argument, &opt[SPORT_OPT_IND], 1},
647 : [DPORT_OPT_IND] = {"dport", required_argument, &opt[DPORT_OPT_IND], 1},
648 : [L3_VXLAN_OPT_IND] = {"l3_vxlan", required_argument, &opt[L3_VXLAN_OPT_IND], 1},
649 : [UDP_OPT_IND] = {"udp", no_argument, &opt[UDP_OPT_IND], 1},
650 : [VXLAN_OPT_IND] = {"vxlan", no_argument, &opt[VXLAN_OPT_IND], 1},
651 : [CNI_OPT_IND] = {"cni", required_argument, &opt[CNI_OPT_IND], 1},
652 : [CMC_OPT_IND] = {"cmc", no_argument, &opt[CMC_OPT_IND], 1},
653 : [CFA_OPT_IND] = {"cfa", no_argument, &opt[CFA_OPT_IND], 1},
654 : [MC_OPT_IND] = {"mc", no_argument, &opt[MC_OPT_IND], 1},
655 : [CEN_OPT_IND] = {"cen", no_argument, &opt[CEN_OPT_IND], 1},
656 : [CEVPN_OPT_IND] = {"cevpn", no_argument, &opt[CEVPN_OPT_IND], 1},
657 : [TOR_OPT_IND] = {"tor", no_argument, &opt[TOR_OPT_IND], 1},
658 : [RLKUP_OPT_IND] = {"rlkup", no_argument, &opt[RLKUP_OPT_IND], 1},
659 : [LBL_OPT_IND] = {"lbl", required_argument, &opt[LBL_OPT_IND], 1},
660 : [UUCF_OPT_IND] = {"uucf", no_argument, &opt[UUCF_OPT_IND], 1},
661 : [LST_OPT_IND] = {"list", no_argument, &opt[LST_OPT_IND], 1},
662 : [GET_OPT_IND] = {"get", required_argument, &opt[GET_OPT_IND], 1},
663 : [CRT_OPT_IND] = {"create", required_argument, &opt[CRT_OPT_IND], 1},
664 : [DEL_OPT_IND] = {"delete", required_argument, &opt[DEL_OPT_IND], 1},
665 : [CMD_OPT_IND] = {"cmd", no_argument, &opt[CMD_OPT_IND], 1},
666 : [IND_OPT_IND] = {"ind", no_argument, &opt[IND_OPT_IND], 1},
667 : [PBB_OPT_IND] = {"pbb", no_argument, &opt[PBB_OPT_IND], 1},
668 : [ROOT_OPT_IND] = {"root", no_argument, &opt[ROOT_OPT_IND], 1},
669 : [ML_OPT_IND] = {"ml", no_argument, &opt[ML_OPT_IND], 1},
670 : [HLP_OPT_IND] = {"help", no_argument, &opt[HLP_OPT_IND], 1},
671 : [SOCK_DIR_OPT_IND] = {"sock-dir", required_argument, &opt[SOCK_DIR_OPT_IND], 1},
672 : [ECMP_OPT_IND] = {"ecmp", no_argument, &opt[ECMP_OPT_IND], 1},
673 : [MAX_OPT_IND] = { NULL, 0, 0, 0}
674 : };
675 :
676 : static void
677 8 : parse_long_opts(int ind, char *opt_arg)
678 : {
679 : int errno, i;
680 : char *c;
681 : struct ether_addr *mac;
682 :
683 8 : errno = 0;
684 8 : switch (ind) {
685 0 : case CMD_OPT_IND:
686 0 : cmd_usage();
687 0 : break;
688 :
689 0 : case HLP_OPT_IND:
690 0 : usage();
691 0 : break;
692 :
693 4 : case GET_OPT_IND:
694 : case CRT_OPT_IND:
695 : case DEL_OPT_IND:
696 4 : nh_id = strtoul(opt_arg, NULL, 0);
697 4 : if (errno)
698 0 : usage();
699 4 : nh_set = 1;
700 4 : break;
701 :
702 0 : case OIF_OPT_IND:
703 0 : count = 0;
704 0 : i = 0;
705 0 : c = strtok(opt_arg, ",");
706 0 : while (c != NULL) {
707 0 : if_id[i++] = atoi(c);
708 0 : c = strtok(NULL, ",");
709 : }
710 0 : count = i;
711 0 : if (errno)
712 0 : usage();
713 0 : break;
714 :
715 0 : case SMAC_OPT_IND:
716 0 : c = NULL;
717 0 : i = 0;
718 0 : c = strtok(opt_arg, ",");
719 0 : while (c != NULL) {
720 0 : mac = ether_aton(c);
721 0 : if (mac)
722 0 : memcpy(src_mac[i], mac, sizeof(src_mac[i]));
723 : else
724 0 : cmd_usage();
725 0 : c = strtok(NULL, ",");
726 0 : i++;
727 0 : mac = NULL;
728 : }
729 0 : break;
730 :
731 0 : case DMAC_OPT_IND:
732 0 : c = NULL;
733 0 : i = 0;
734 0 : c = strtok(opt_arg, ",");
735 0 : while (c != NULL) {
736 0 : mac = ether_aton(c);
737 0 : if (mac)
738 0 : memcpy(dst_mac[i], mac, sizeof(dst_mac[i]));
739 : else
740 0 : cmd_usage();
741 0 : c = strtok(NULL, ",");
742 0 : i++;
743 0 : mac = NULL;
744 : }
745 0 : break;
746 :
747 0 : case VRF_OPT_IND:
748 0 : vrf_id = strtoul(opt_arg, NULL, 0);
749 0 : if (errno)
750 0 : usage();
751 0 : break;
752 :
753 0 : case TYPE_OPT_IND:
754 0 : type = strtoul(opt_arg, NULL, 0);
755 0 : if (errno)
756 0 : usage();
757 0 : break;
758 :
759 0 : case SIP_OPT_IND:
760 0 : inet_aton(opt_arg, &sip);
761 0 : break;
762 :
763 0 : case DIP_OPT_IND:
764 0 : inet_aton(opt_arg, &dip);
765 0 : break;
766 :
767 0 : case SPORT_OPT_IND:
768 0 : sport = strtoul(opt_arg, NULL, 0);
769 0 : if (errno)
770 0 : usage();
771 0 : break;
772 :
773 0 : case CNI_OPT_IND:
774 0 : comp_nh[comp_nh_ind++] = strtoul(opt_arg, NULL, 0);
775 0 : if (errno)
776 0 : usage();
777 0 : break;
778 :
779 0 : case LBL_OPT_IND:
780 0 : lbl[lbl_ind++] = strtoul(opt_arg, NULL, 0);
781 0 : if (errno)
782 0 : usage();
783 0 : break;
784 :
785 0 : case DPORT_OPT_IND:
786 0 : dport = strtoul(opt_arg, NULL, 0);
787 0 : if (errno)
788 0 : usage();
789 0 : break;
790 0 : case L3_VXLAN_OPT_IND:
791 0 : mac = ether_aton(opt_arg);
792 0 : if (mac)
793 0 : memcpy(l3_vxlan_mac, mac, sizeof(l3_vxlan_mac));
794 : else
795 0 : cmd_usage();
796 0 : break;
797 4 : case SOCK_DIR_OPT_IND:
798 4 : vr_socket_dir = opt_arg;
799 4 : break;
800 : }
801 :
802 8 : return;
803 : }
804 :
805 : static void
806 4 : validate_options(void)
807 : {
808 4 : if (opt_set(CRT_OPT_IND)) {
809 0 : command = SANDESH_OP_ADD;
810 4 : } else if (opt_set(DEL_OPT_IND)) {
811 0 : command = SANDESH_OP_DEL;
812 4 : } else if (opt_set(GET_OPT_IND)) {
813 4 : command = SANDESH_OP_GET;
814 0 : } else if (opt_set(LST_OPT_IND)) {
815 0 : command = SANDESH_OP_DUMP;
816 : } else {
817 0 : usage();
818 0 : return;
819 : }
820 :
821 :
822 4 : switch (command) {
823 0 : case SANDESH_OP_ADD:
824 0 : if (!nh_set)
825 0 : cmd_usage();
826 :
827 0 : flags |= NH_FLAG_VALID;
828 0 : if (!opt_set(TYPE_OPT_IND))
829 0 : cmd_usage();
830 :
831 0 : if(!opt_set(VRF_OPT_IND))
832 0 : cmd_usage();
833 :
834 0 : if (opt_set(MC_OPT_IND))
835 0 : flags |= NH_FLAG_MCAST;
836 :
837 0 : if (opt_set(POL_OPT_IND))
838 0 : flags |= NH_FLAG_POLICY_ENABLED;
839 :
840 0 : if (opt_set(IND_OPT_IND))
841 0 : flags |= NH_FLAG_INDIRECT;
842 :
843 0 : if (opt_set(RPOL_OPT_IND))
844 0 : flags |= NH_FLAG_RELAXED_POLICY;
845 :
846 0 : if (opt_set(L2_OPT_IND))
847 0 : family = AF_BRIDGE;
848 :
849 0 : if (opt_set(RLKUP_OPT_IND))
850 0 : flags |= NH_FLAG_ROUTE_LOOKUP;
851 :
852 0 : if (opt_set(ML_OPT_IND))
853 0 : flags |= NH_FLAG_MAC_LEARN;
854 :
855 0 : if (opt_set(ROOT_OPT_IND))
856 0 : flags |= NH_FLAG_ETREE_ROOT;
857 :
858 0 : if (type == NH_RCV) {
859 0 : if (!opt_set(OIF_OPT_IND))
860 0 : cmd_usage();
861 :
862 0 : if (memcmp(opt, zero_opt, sizeof(opt)))
863 0 : cmd_usage();
864 0 : } else if (type == NH_L2_RCV) {
865 0 : if (memcmp(opt, zero_opt, sizeof(opt)))
866 0 : cmd_usage();
867 0 : } else if (type == NH_ENCAP) {
868 0 : if (!opt_set(OIF_OPT_IND))
869 0 : cmd_usage();
870 :
871 0 : if (family == AF_INET) {
872 0 : if (!opt_set(SMAC_OPT_IND) || !opt_set(DMAC_OPT_IND))
873 0 : cmd_usage();
874 :
875 0 : if (opt_set(L3_VXLAN_OPT_IND))
876 0 : flags |= NH_FLAG_L3_VXLAN;
877 :
878 0 : if (memcmp(opt, zero_opt, sizeof(opt)))
879 0 : cmd_usage();
880 : }
881 :
882 0 : } else if (type == NH_TUNNEL) {
883 :
884 0 : if (count > 1)
885 0 : flags |= NH_FLAG_TUNNEL_UNDERLAY_ECMP;
886 :
887 0 : if (opt_set(PBB_OPT_IND)) {
888 0 : if (!opt_set(CNI_OPT_IND)) {
889 0 : cmd_usage();
890 : }
891 :
892 0 : if (comp_nh_ind != 1)
893 0 : cmd_usage();
894 :
895 0 : if (!opt_set(LBL_OPT_IND) || !opt_set(DMAC_OPT_IND))
896 0 : cmd_usage();
897 :
898 0 : flags |= NH_FLAG_TUNNEL_PBB;
899 :
900 0 : } else if (!opt_set(OIF_OPT_IND) || !opt_set(SMAC_OPT_IND) ||
901 0 : !opt_set(DMAC_OPT_IND) || !opt_set(SIP_OPT_IND) ||
902 0 : !opt_set(DIP_OPT_IND)) {
903 0 : cmd_usage();
904 : }
905 :
906 0 : if (opt_set(UDP_OPT_IND)) {
907 0 : if (!opt_set(SPORT_OPT_IND) || !opt_set(DPORT_OPT_IND))
908 0 : flags |= NH_FLAG_TUNNEL_UDP_MPLS;
909 : else
910 0 : flags |= NH_FLAG_TUNNEL_UDP;
911 0 : } else if (opt_set(VXLAN_OPT_IND)) {
912 0 : flags |= NH_FLAG_TUNNEL_VXLAN;
913 0 : if (!opt_set(SPORT_OPT_IND) || !opt_set(DPORT_OPT_IND))
914 0 : cmd_usage();
915 0 : if (opt_set(L3_VXLAN_OPT_IND))
916 0 : flags |= NH_FLAG_L3_VXLAN;
917 : }
918 :
919 0 : if (!(flags & (NH_FLAG_TUNNEL_UDP_MPLS | NH_FLAG_TUNNEL_UDP |
920 : NH_FLAG_TUNNEL_VXLAN | NH_FLAG_TUNNEL_PBB)))
921 0 : flags |= NH_FLAG_TUNNEL_GRE;
922 :
923 0 : if (memcmp(opt, zero_opt, sizeof(opt)))
924 0 : cmd_usage();
925 0 : } else if (type == NH_RESOLVE) {
926 0 : if (memcmp(opt, zero_opt, sizeof(opt)))
927 0 : cmd_usage();
928 0 : } else if (type == NH_DISCARD) {
929 0 : if (memcmp(opt, zero_opt, sizeof(opt)))
930 0 : cmd_usage();
931 0 : } else if (type == NH_COMPOSITE) {
932 0 : if (!opt_set(CNI_OPT_IND))
933 0 : cmd_usage();
934 :
935 0 : if (opt_set(CMC_OPT_IND)) {
936 0 : flags |= NH_FLAG_MCAST;
937 : }
938 :
939 0 : if (opt_set(CFA_OPT_IND))
940 0 : flags |= NH_FLAG_COMPOSITE_FABRIC;
941 :
942 0 : if (opt_set(CEN_OPT_IND))
943 0 : flags |= NH_FLAG_COMPOSITE_ENCAP;
944 :
945 0 : if (opt_set(CEVPN_OPT_IND)) {
946 0 : flags |= NH_FLAG_COMPOSITE_EVPN;
947 :
948 0 : if (!opt_set(LBL_OPT_IND))
949 0 : cmd_usage();
950 : }
951 :
952 0 : if (opt_set(TOR_OPT_IND)) {
953 0 : flags |= NH_FLAG_COMPOSITE_TOR;
954 :
955 0 : if (!opt_set(LBL_OPT_IND))
956 0 : cmd_usage();
957 : }
958 :
959 0 : if (opt_set(ECMP_OPT_IND)) {
960 0 : flags |= NH_FLAG_COMPOSITE_ECMP;
961 : }
962 :
963 0 : if (memcmp(opt, zero_opt, sizeof(opt)))
964 0 : cmd_usage();
965 :
966 0 : } else if (type == NH_VRF_TRANSLATE) {
967 0 : if (opt_set(UUCF_OPT_IND))
968 0 : flags |= NH_FLAG_UNKNOWN_UC_FLOOD;
969 : } else {
970 0 : cmd_usage();
971 : }
972 :
973 0 : break;
974 :
975 0 : case SANDESH_OP_DEL:
976 0 : if (!nh_set)
977 0 : cmd_usage();
978 :
979 0 : if (memcmp(opt, zero_opt, sizeof(opt)))
980 0 : cmd_usage();
981 0 : break;
982 :
983 4 : case SANDESH_OP_DUMP:
984 : case SANDESH_OP_GET:
985 4 : if (memcmp(opt, zero_opt, sizeof(opt)))
986 0 : usage();
987 4 : break;
988 : }
989 :
990 4 : return;
991 : }
992 :
993 :
994 : int
995 4 : main(int argc, char *argv[])
996 : {
997 : int opt, ind;
998 :
999 4 : nh_fill_nl_callbacks();
1000 :
1001 12 : while ((opt = getopt_long(argc, argv, "",
1002 12 : long_options, &ind)) >= 0) {
1003 8 : switch (opt) {
1004 8 : case 0:
1005 8 : parse_long_opts(ind, optarg);
1006 8 : break;
1007 :
1008 0 : default:
1009 0 : usage();
1010 : }
1011 : }
1012 :
1013 4 : if (opt_set(SOCK_DIR_OPT_IND)) {
1014 4 : set_platform_vtest();
1015 : }
1016 4 : validate_options();
1017 :
1018 4 : cl = vr_get_nl_client(VR_NETLINK_PROTO_DEFAULT);
1019 4 : if (!cl) {
1020 0 : exit(1);
1021 : }
1022 :
1023 4 : vr_nh_op(cl, command, type, nh_id, if_id, vrf_id, dst_mac,
1024 : src_mac, sip, dip, flags);
1025 :
1026 4 : return 0;
1027 : }
|