LCOV - code coverage report
Current view: top level - plugins/nat/pnat - pnat_cli.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 77 201 38.3 %
Date: 2023-10-26 01:39:38 Functions: 13 16 81.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2021 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <stdbool.h>
      17             : #include <vlib/vlib.h>
      18             : #include <vnet/feature/feature.h>
      19             : #include <vnet/ip/ip.h>
      20             : #include <vnet/ip/ip4.h>
      21             : #include <vnet/ip/ip4_packet.h>
      22             : #include <vppinfra/clib_error.h>
      23             : #include <vppinfra/pool.h>
      24             : #include "pnat.h"
      25             : 
      26             : /*
      27             :  * This file contains the handlers for the (unsupported) VPP debug CLI.
      28             :  */
      29          11 : u8 *format_pnat_match_tuple(u8 *s, va_list *args) {
      30          11 :     pnat_match_tuple_t *t = va_arg(*args, pnat_match_tuple_t *);
      31          11 :     s = format(s, "{");
      32          11 :     if (t->mask & PNAT_SA)
      33           4 :         s = format(s, "%U", format_ip4_address, &t->src);
      34             :     else
      35           7 :         s = format(s, "*");
      36          11 :     if (t->mask & PNAT_SPORT)
      37           0 :         s = format(s, ":%u,", t->sport);
      38             :     else
      39          11 :         s = format(s, ":*,");
      40          11 :     if (t->proto > 0)
      41           7 :         s = format(s, "%U,", format_ip_protocol, t->proto);
      42             :     else
      43           4 :         s = format(s, "*,");
      44          11 :     if (t->mask & PNAT_DA)
      45           7 :         s = format(s, "%U", format_ip4_address, &t->dst);
      46             :     else
      47           4 :         s = format(s, "*");
      48          11 :     if (t->mask & PNAT_DPORT)
      49           6 :         s = format(s, ":%u", t->dport);
      50             :     else
      51           5 :         s = format(s, ":*");
      52          11 :     s = format(s, "}");
      53          11 :     return s;
      54             : }
      55          11 : u8 *format_pnat_rewrite_tuple(u8 *s, va_list *args) {
      56          11 :     pnat_rewrite_tuple_t *t = va_arg(*args, pnat_rewrite_tuple_t *);
      57          11 :     s = format(s, "{");
      58          11 :     if (t->mask & PNAT_SA)
      59           5 :         s = format(s, "%U", format_ip4_address, &t->src);
      60             :     else
      61           6 :         s = format(s, "*");
      62          11 :     if (t->mask & PNAT_SPORT)
      63           0 :         s = format(s, ":%u,", t->sport);
      64             :     else
      65          11 :         s = format(s, ":*,");
      66          11 :     if (t->mask & PNAT_DA)
      67           5 :         s = format(s, "%U", format_ip4_address, &t->dst);
      68             :     else
      69           6 :         s = format(s, "*");
      70          11 :     if (t->mask & PNAT_DPORT)
      71           2 :         s = format(s, ":%u", t->dport);
      72             :     else
      73           9 :         s = format(s, ":*");
      74          11 :     if (t->mask & PNAT_COPY_BYTE)
      75           0 :         s = format(s, " copy byte@[%d->%d]", t->from_offset, t->to_offset);
      76          11 :     if (t->mask & PNAT_CLEAR_BYTE)
      77           0 :         s = format(s, " clear byte@[%d]", t->clear_offset);
      78          11 :     s = format(s, "}");
      79          11 :     return s;
      80             : }
      81             : 
      82           2 : u8 *format_pnat_translation(u8 *s, va_list *args) {
      83           2 :     u32 index = va_arg(*args, u32);
      84           2 :     pnat_translation_t *t = va_arg(*args, pnat_translation_t *);
      85           2 :     s = format(s, "[%d] match: %U rewrite: %U", index, format_pnat_match_tuple,
      86             :                &t->match, format_pnat_rewrite_tuple, &t->rewrite);
      87           2 :     return s;
      88             : }
      89             : 
      90           2 : static u8 *format_pnat_mask(u8 *s, va_list *args) {
      91           2 :     pnat_mask_t t = va_arg(*args, pnat_mask_t);
      92           2 :     if (t & PNAT_SA)
      93           1 :         s = format(s, "SA ");
      94           2 :     if (t & PNAT_SPORT)
      95           0 :         s = format(s, "SP ");
      96           2 :     if (t & PNAT_DA)
      97           1 :         s = format(s, "DA ");
      98           2 :     if (t & PNAT_DPORT)
      99           2 :         s = format(s, "DP");
     100           2 :     return s;
     101             : }
     102             : 
     103           2 : static u8 *format_pnat_interface(u8 *s, va_list *args) {
     104           2 :     pnat_interface_t *interface = va_arg(*args, pnat_interface_t *);
     105           2 :     s = format(s, "sw_if_index: %d", interface->sw_if_index);
     106           2 :     if (interface->enabled[PNAT_IP4_INPUT]) {
     107           1 :         s = format(s, " input mask: %U", format_pnat_mask,
     108           1 :                    interface->lookup_mask[PNAT_IP4_INPUT]);
     109             :     }
     110           2 :     if (interface->enabled[PNAT_IP4_OUTPUT]) {
     111           1 :         s = format(s, " output mask: %U", format_pnat_mask,
     112           1 :                    interface->lookup_mask[PNAT_IP4_OUTPUT]);
     113             :     }
     114           2 :     return s;
     115             : }
     116             : 
     117           0 : uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) {
     118           0 :     pnat_match_tuple_t *t = va_arg(*args, pnat_match_tuple_t *);
     119             :     u32 dport, sport;
     120             :     while (1) {
     121           0 :         if (unformat(input, "src %U", unformat_ip4_address, &t->src))
     122           0 :             t->mask |= PNAT_SA;
     123           0 :         else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
     124           0 :             t->mask |= PNAT_DA;
     125           0 :         else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto))
     126           0 :             t->mask |= PNAT_PROTO;
     127           0 :         else if (unformat(input, "sport %d", &sport)) {
     128           0 :             if (sport == 0 || sport > 65535)
     129           0 :                 return 0;
     130           0 :             t->mask |= PNAT_SPORT;
     131           0 :             t->sport = sport;
     132           0 :         } else if (unformat(input, "dport %d", &dport)) {
     133           0 :             if (dport == 0 || dport > 65535)
     134           0 :                 return 0;
     135           0 :             t->mask |= PNAT_DPORT;
     136           0 :             t->dport = dport;
     137             :         } else
     138           0 :             break;
     139             :     }
     140           0 :     return 1;
     141             : }
     142             : 
     143           0 : uword unformat_pnat_rewrite_tuple(unformat_input_t *input, va_list *args) {
     144           0 :     pnat_rewrite_tuple_t *t = va_arg(*args, pnat_rewrite_tuple_t *);
     145             :     u32 dport, sport;
     146             :     u32 to_offset, from_offset, clear_offset;
     147             : 
     148             :     while (1) {
     149           0 :         if (unformat(input, "src %U", unformat_ip4_address, &t->src))
     150           0 :             t->mask |= PNAT_SA;
     151           0 :         else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst))
     152           0 :             t->mask |= PNAT_DA;
     153           0 :         else if (unformat(input, "sport %d", &sport)) {
     154           0 :             if (sport == 0 || sport > 65535)
     155           0 :                 return 0;
     156           0 :             t->mask |= PNAT_SPORT;
     157           0 :             t->sport = sport;
     158           0 :         } else if (unformat(input, "dport %d", &dport)) {
     159           0 :             if (dport == 0 || dport > 65535)
     160           0 :                 return 0;
     161           0 :             t->mask |= PNAT_DPORT;
     162           0 :             t->dport = dport;
     163           0 :         } else if (unformat(input, "copy-byte-at-offset %d %d", &from_offset,
     164             :                             &to_offset)) {
     165           0 :             if (from_offset == to_offset || to_offset > 255 ||
     166           0 :                 from_offset > 255)
     167           0 :                 return 0;
     168           0 :             t->mask |= PNAT_COPY_BYTE;
     169           0 :             t->from_offset = from_offset;
     170           0 :             t->to_offset = to_offset;
     171           0 :         } else if (unformat(input, "clear-byte-at-offset %d", &clear_offset)) {
     172           0 :             if (clear_offset > 255)
     173           0 :                 return 0;
     174           0 :             t->mask |= PNAT_CLEAR_BYTE;
     175           0 :             t->clear_offset = clear_offset;
     176             :         } else
     177           0 :             break;
     178             :     }
     179           0 :     return 1;
     180             : }
     181             : 
     182           0 : static clib_error_t *set_pnat_translation_command_fn(vlib_main_t *vm,
     183             :                                                      unformat_input_t *input,
     184             :                                                      vlib_cli_command_t *cmd) {
     185           0 :     unformat_input_t _line_input, *line_input = &_line_input;
     186           0 :     clib_error_t *error = 0;
     187           0 :     bool in = false, out = false;
     188           0 :     bool match_set = false, rewrite_set = false;
     189           0 :     bool add = true;
     190           0 :     u32 sw_if_index = ~0;
     191           0 :     pnat_match_tuple_t match = {0};
     192           0 :     pnat_rewrite_tuple_t rewrite = {0};
     193             : 
     194             :     /* Get a line of input. */
     195           0 :     if (!unformat_user(input, unformat_line_input, line_input))
     196           0 :         return 0;
     197             : 
     198           0 :     while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
     199           0 :         if (unformat(line_input, "match %U", unformat_pnat_match_tuple, &match))
     200           0 :             match_set = true;
     201           0 :         else if (unformat(line_input, "rewrite %U", unformat_pnat_rewrite_tuple,
     202             :                           &rewrite))
     203           0 :             rewrite_set = true;
     204           0 :         else if (unformat(line_input, "interface %U",
     205             :                           unformat_vnet_sw_interface, vnet_get_main(),
     206             :                           &sw_if_index))
     207             :             ;
     208           0 :         else if (unformat(line_input, "in")) {
     209           0 :             in = true;
     210           0 :         } else if (unformat(line_input, "out")) {
     211           0 :             out = true;
     212           0 :         } else if (unformat(line_input, "del")) {
     213           0 :             add = false;
     214             :         } else {
     215           0 :             error = clib_error_return(0, "unknown input `%U'",
     216             :                                       format_unformat_error, line_input);
     217           0 :             goto done;
     218             :         }
     219             :     }
     220           0 :     if (sw_if_index == ~0) {
     221           0 :         error = clib_error_return(0, "interface is required `%U'",
     222             :                                   format_unformat_error, line_input);
     223           0 :         goto done;
     224             :     }
     225           0 :     if ((in && out) || (!in && !out)) {
     226           0 :         error = clib_error_return(0, "in or out is required `%U'",
     227             :                                   format_unformat_error, line_input);
     228           0 :         goto done;
     229             :     }
     230           0 :     if (!match_set) {
     231           0 :         error = clib_error_return(0, "missing parameter: match `%U'",
     232             :                                   format_unformat_error, line_input);
     233           0 :         goto done;
     234             :     }
     235           0 :     if (!rewrite_set) {
     236           0 :         error = clib_error_return(0, "missing parameter: rewrite `%U'",
     237             :                                   format_unformat_error, line_input);
     238           0 :         goto done;
     239             :     }
     240             : 
     241           0 :     if ((match.dport || match.sport) &&
     242           0 :         (match.proto != 17 && match.proto != 6)) {
     243           0 :         error = clib_error_return(0, "missing protocol (TCP|UDP): match `%U'",
     244             :                                   format_unformat_error, line_input);
     245           0 :         goto done;
     246             :     }
     247           0 :     pnat_attachment_point_t attachment = in ? PNAT_IP4_INPUT : PNAT_IP4_OUTPUT;
     248             : 
     249           0 :     if (add) {
     250             :         u32 binding_index;
     251           0 :         int rv = pnat_binding_add(&match, &rewrite, &binding_index);
     252           0 :         if (rv) {
     253           0 :             error = clib_error_return(0, "Adding binding failed %d", rv);
     254           0 :             goto done;
     255             :         }
     256           0 :         rv = pnat_binding_attach(sw_if_index, attachment, binding_index);
     257           0 :         if (rv) {
     258           0 :             pnat_binding_del(binding_index);
     259           0 :             error = clib_error_return(
     260             :                 0, "Attaching binding to interface failed %d", rv);
     261           0 :             goto done;
     262             :         }
     263             :     } else {
     264             :         /* Lookup binding and lookup interface if both exists proceed with
     265             :          * delete */
     266           0 :         u32 binding_index = pnat_flow_lookup(sw_if_index, attachment, &match);
     267           0 :         if (binding_index == ~0) {
     268           0 :             error = clib_error_return(0, "Binding does not exist");
     269           0 :             goto done;
     270             :         }
     271           0 :         pnat_attachment_point_t attachment =
     272           0 :             in ? PNAT_IP4_INPUT : PNAT_IP4_OUTPUT;
     273           0 :         int rv = pnat_binding_detach(sw_if_index, attachment, binding_index);
     274           0 :         if (rv) {
     275           0 :             error = clib_error_return(0, "Detaching binding failed %d %d",
     276             :                                       binding_index, rv);
     277           0 :             goto done;
     278             :         }
     279           0 :         rv = pnat_binding_del(binding_index);
     280           0 :         if (rv) {
     281           0 :             error = clib_error_return(0, "Deleting translation failed %d %d",
     282             :                                       binding_index, rv);
     283           0 :             goto done;
     284             :         }
     285             :     }
     286             : 
     287           0 : done:
     288           0 :     unformat_free(line_input);
     289             : 
     290           0 :     return error;
     291             : }
     292             : 
     293       50261 : VLIB_CLI_COMMAND(set_pnat_translation_command, static) = {
     294             :     .path = "set pnat translation",
     295             :     .short_help = "set pnat translation interface <name> match <5-tuple> "
     296             :                   "rewrite <tuple> {in|out} [del]",
     297             :     .function = set_pnat_translation_command_fn,
     298             : };
     299             : 
     300             : static clib_error_t *
     301           1 : show_pnat_translations_command_fn(vlib_main_t *vm, unformat_input_t *input,
     302             :                                   vlib_cli_command_t *cmd) {
     303           1 :     pnat_main_t *pm = &pnat_main;
     304             :     pnat_translation_t *s;
     305           1 :     clib_error_t *error = 0;
     306             : 
     307             :     /* Get a line of input. */
     308           3 :     pool_foreach(s, pm->translations) {
     309           2 :         vlib_cli_output(vm, "%U", format_pnat_translation, s - pm->translations,
     310             :                         s);
     311             :     }
     312           1 :     return error;
     313             : }
     314             : 
     315       50261 : VLIB_CLI_COMMAND(show_pnat_translations_command, static) = {
     316             :     .path = "show pnat translations",
     317             :     .short_help = "show pnat translations",
     318             :     .function = show_pnat_translations_command_fn,
     319             : };
     320             : 
     321           1 : static clib_error_t *show_pnat_interfaces_command_fn(vlib_main_t *vm,
     322             :                                                      unformat_input_t *input,
     323             :                                                      vlib_cli_command_t *cmd) {
     324           1 :     pnat_main_t *pm = &pnat_main;
     325             :     pnat_interface_t *interface;
     326           1 :     clib_error_t *error = 0;
     327             : 
     328             :     /* Get a line of input. */
     329           3 :     pool_foreach(interface, pm->interfaces) {
     330           2 :         vlib_cli_output(vm, "%U", format_pnat_interface, interface);
     331             :     }
     332           1 :     return error;
     333             : }
     334             : 
     335       50261 : VLIB_CLI_COMMAND(show_pnat_interfaces_command, static) = {
     336             :     .path = "show pnat interfaces",
     337             :     .short_help = "show pnat interfaces",
     338             :     .function = show_pnat_interfaces_command_fn,
     339             : };

Generated by: LCOV version 1.14