summaryrefslogtreecommitdiffstats
path: root/src/plugins/cnat
diff options
context:
space:
mode:
authorNathan Skrzypczak <nathan.skrzypczak@gmail.com>2021-02-25 17:42:50 +0100
committerDave Barach <openvpp@barachs.net>2021-03-04 12:35:15 +0000
commit516b0adf6d8bbc6533ab58d7add96ec74d8be05a (patch)
tree57cc09232a708ee6510ded4f00c3e9e0745e3b8e /src/plugins/cnat
parent3fd77f7dea1ac91c5b4c9ede69b992a4e2243153 (diff)
cnat: Add calico/k8s src policy
This patch implements k8s-specific extensions to the cnat plugin. This could be done by exposing a richer semantic on srcNAT policies, but this might be too complex work at this point. Also k8s fits quite well as a 'cloud NAT' usecase. Type: feature Change-Id: I2266daf7b10a92e65f5ed430838a12ae826bd333 Signed-off-by: Aloys Augustin <aloaugus@cisco.com> Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
Diffstat (limited to 'src/plugins/cnat')
-rw-r--r--src/plugins/cnat/cnat.api3
-rw-r--r--src/plugins/cnat/cnat_snat_policy.c56
-rw-r--r--src/plugins/cnat/cnat_snat_policy.h2
3 files changed, 59 insertions, 2 deletions
diff --git a/src/plugins/cnat/cnat.api b/src/plugins/cnat/cnat.api
index df57ea54896..e253084e74e 100644
--- a/src/plugins/cnat/cnat.api
+++ b/src/plugins/cnat/cnat.api
@@ -171,6 +171,7 @@ enum cnat_snat_policy_table:u8
{
CNAT_POLICY_INCLUDE_V4 = 0,
CNAT_POLICY_INCLUDE_V6 = 1,
+ CNAT_POLICY_POD = 2,
};
autoreply define cnat_snat_policy_add_del_if
@@ -190,6 +191,8 @@ enum cnat_snat_policies:u8
/* Filter by interface list : snat_policy_add_del_if
* and prefix list : snat_policy_add_del_if */
CNAT_POLICY_IF_PFX = 1,
+ /* Kubernetes specific policy */
+ CNAT_POLICY_K8S = 2,
};
autoreply define cnat_set_snat_policy
diff --git a/src/plugins/cnat/cnat_snat_policy.c b/src/plugins/cnat/cnat_snat_policy.c
index 83a79c0544d..e2901631b28 100644
--- a/src/plugins/cnat/cnat_snat_policy.c
+++ b/src/plugins/cnat/cnat_snat_policy.c
@@ -27,6 +27,8 @@ unformat_cnat_snat_interface_map_type (unformat_input_t *input, va_list *args)
*a = CNAT_SNAT_IF_MAP_INCLUDE_V4;
else if (unformat (input, "include-v6"))
*a = CNAT_SNAT_IF_MAP_INCLUDE_V6;
+ else if (unformat (input, "k8s"))
+ *a = CNAT_SNAT_IF_MAP_INCLUDE_POD;
else
return 0;
return 1;
@@ -44,6 +46,9 @@ format_cnat_snat_interface_map_type (u8 *s, va_list *args)
case CNAT_SNAT_IF_MAP_INCLUDE_V6:
s = format (s, "Included v6");
break;
+ case CNAT_SNAT_IF_MAP_INCLUDE_POD:
+ s = format (s, "k8s pod");
+ break;
default:
s = format (s, "(unknown)");
break;
@@ -135,7 +140,7 @@ cnat_snat_policy_add_del_if_command_fn (vlib_main_t *vm,
VLIB_CLI_COMMAND (cnat_snat_policy_add_del_if_command, static) = {
.path = "set cnat snat-policy if",
.short_help = "set cnat snat-policy if [del]"
- "[table [include-v4 include-v6]] [interface]",
+ "[table [include-v4 include-v6 k8s]] [interface]",
.function = cnat_snat_policy_add_del_if_command_fn,
};
@@ -280,6 +285,48 @@ cnat_snat_policy_if_pfx (vlib_buffer_t *b, cnat_session_t *session)
return 0;
}
+int
+cnat_snat_policy_k8s (vlib_buffer_t *b, cnat_session_t *session)
+{
+ cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
+ ip_address_family_t af = session->key.cs_af;
+
+ ip46_address_t *src_addr = &session->key.cs_ip[VLIB_RX];
+ ip46_address_t *dst_addr = &session->key.cs_ip[VLIB_TX];
+ u32 in_if = vnet_buffer (b)->sw_if_index[VLIB_RX];
+ u32 out_if = vnet_buffer (b)->sw_if_index[VLIB_TX];
+
+ /* source nat for outgoing connections */
+ if (cnat_snat_policy_interface_enabled (in_if, af))
+ if (cnat_search_snat_prefix (dst_addr, af))
+ /* Destination is not in the prefixes that don't require snat */
+ return 1;
+
+ /* source nat for translations that come from the outside:
+ src not not a pod interface, dst not a pod interface */
+ if (!clib_bitmap_get (cpm->interface_maps[CNAT_SNAT_IF_MAP_INCLUDE_POD],
+ in_if) &&
+ !clib_bitmap_get (cpm->interface_maps[CNAT_SNAT_IF_MAP_INCLUDE_POD],
+ out_if))
+ {
+ if (AF_IP6 == af &&
+ ip6_address_is_equal (&src_addr->ip6,
+ &ip_addr_v6 (&cpm->snat_ip6.ce_ip)))
+ return 0;
+ if (AF_IP4 == af &&
+ ip4_address_is_equal (&src_addr->ip4,
+ &ip_addr_v4 (&cpm->snat_ip4.ce_ip)))
+ return 0;
+ return 1;
+ }
+
+ /* handle the case where a container is connecting to itself via a service */
+ if (ip46_address_is_equal (src_addr, dst_addr))
+ return 1;
+
+ return 0;
+}
+
void
cnat_set_snat (ip4_address_t *ip4, ip6_address_t *ip6, u32 sw_if_index)
{
@@ -434,6 +481,9 @@ cnat_set_snat_policy (cnat_snat_policy_type_t policy)
case CNAT_SNAT_POLICY_IF_PFX:
cpm->snat_policy = cnat_snat_policy_if_pfx;
break;
+ case CNAT_SNAT_POLICY_K8S:
+ cpm->snat_policy = cnat_snat_policy_k8s;
+ break;
default:
return 1;
}
@@ -451,6 +501,8 @@ cnat_snat_policy_set_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
;
else if (unformat (input, "if-pfx"))
policy = CNAT_SNAT_POLICY_IF_PFX;
+ else if (unformat (input, "k8s"))
+ policy = CNAT_SNAT_POLICY_K8S;
else
return clib_error_return (0, "unknown input '%U'",
format_unformat_error, input);
@@ -462,7 +514,7 @@ cnat_snat_policy_set_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
VLIB_CLI_COMMAND (cnat_snat_policy_set_cmd, static) = {
.path = "set cnat snat-policy",
- .short_help = "set cnat snat-policy [none][if-pfx]",
+ .short_help = "set cnat snat-policy [none][if-pfx][k8s]",
.function = cnat_snat_policy_set_cmd_fn,
};
diff --git a/src/plugins/cnat/cnat_snat_policy.h b/src/plugins/cnat/cnat_snat_policy.h
index ff30d19c884..987ae494e16 100644
--- a/src/plugins/cnat/cnat_snat_policy.h
+++ b/src/plugins/cnat/cnat_snat_policy.h
@@ -44,6 +44,7 @@ typedef enum cnat_snat_interface_map_type_t_
{
CNAT_SNAT_IF_MAP_INCLUDE_V4 = AF_IP4,
CNAT_SNAT_IF_MAP_INCLUDE_V6 = AF_IP6,
+ CNAT_SNAT_IF_MAP_INCLUDE_POD,
CNAT_N_SNAT_IF_MAP,
} cnat_snat_interface_map_type_t;
@@ -51,6 +52,7 @@ typedef enum cnat_snat_policy_type_t_
{
CNAT_SNAT_POLICY_NONE = 0,
CNAT_SNAT_POLICY_IF_PFX = 1,
+ CNAT_SNAT_POLICY_K8S = 2,
} cnat_snat_policy_type_t;
typedef struct cnat_snat_policy_main_t_
ont-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * Copyright (c) 2015 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __included_vat_h__
#define __included_vat_h__

#include <stdio.h>
#include <setjmp.h>
#include <vppinfra/clib.h>
#include <vppinfra/format.h>
#include <vppinfra/error.h>
#include <vppinfra/time.h>
#include <vppinfra/macros.h>
#include <vnet/vnet.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>

#include "vat/json_format.h"

#include <vlib/vlib.h>

typedef struct
{
  u8 *interface_name;
  u32 sw_if_index;
  /*
   * Subinterface ID. A number 0-N to uniquely identify this
   * subinterface under the super interface
   */
  u32 sub_id;

  /* 0 = dot1q, 1=dot1ad */
  u8 sub_dot1ad;

  /* Number of tags 0-2 */
  u8 sub_number_of_tags;
  u16 sub_outer_vlan_id;
  u16 sub_inner_vlan_id;
  u8 sub_exact_match;
  u8 sub_default;
  u8 sub_outer_vlan_id_any;
  u8 sub_inner_vlan_id_any;

  /* vlan tag rewrite */
  u32 vtr_op;
  u32 vtr_push_dot1q;
  u32 vtr_tag1;
  u32 vtr_tag2;
} sw_interface_subif_t;

typedef struct
{
  u8 ip[16];
  u8 prefix_length;
} ip_address_details_t;

typedef struct
{
  u8 present;
  ip_address_details_t *addr;
} ip_details_t;

typedef struct
{
  u64 packets;
  u64 bytes;
} interface_counter_t;

typedef struct
{
  struct in_addr address;
  u8 address_length;
  u64 packets;
  u64 bytes;
} ip4_fib_counter_t;

typedef struct
{
  struct in6_addr address;
  u8 address_length;
  u64 packets;
  u64 bytes;
} ip6_fib_counter_t;

typedef struct
{
  struct in_addr address;
  vnet_link_t linkt;
  u64 packets;
  u64 bytes;
} ip4_nbr_counter_t;

typedef struct
{
  struct in6_addr address;
  vnet_link_t linkt;
  u64 packets;
  u64 bytes;
} ip6_nbr_counter_t;

typedef struct
{
  /* vpe input queue */
  unix_shared_memory_queue_t *vl_input_queue;

  /* interface name table */
  uword *sw_if_index_by_interface_name;

  /* subinterface table */
  sw_interface_subif_t *sw_if_subif_table;

  /* Graph node table */
  uword *graph_node_index_by_name;
  vlib_node_t **graph_nodes;

  /* ip tables */
  ip_details_t *ip_details_by_sw_if_index[2];

  /* sw_if_index of currently processed interface */
  u32 current_sw_if_index;

  /* remember that we are dumping ipv6 */
  u8 is_ipv6;

  /* function table */
  uword *function_by_name;

  /* help strings */
  uword *help_by_name;

  /* macro table */
  macro_main_t macro_main;

  /* Errors by number */
  uword *error_string_by_error_number;


  /* Main thread can spin (w/ timeout) here if needed */
  u32 async_mode;
  u32 async_errors;
  volatile u32 result_ready;
  volatile i32 retval;
  volatile u32 sw_if_index;
  volatile u8 *shmem_result;
  volatile u8 *cmd_reply;

  /* our client index */
  u32 my_client_index;

  /* Time is of the essence... */
  clib_time_t clib_time;

  /* Unwind (so we can quit) */
  jmp_buf jump_buf;
  int jump_buf_set;
  volatile int do_exit;

  /* temporary parse buffer */
  unformat_input_t *input;

  /* input buffer */
  u8 *inbuf;

  /* stdio input / output FILEs */
  FILE *ifp, *ofp;
  u8 *current_file;
  u32 input_line_number;

  /* exec mode toggle */
  int exec_mode;

  /* Regenerate the interface table */
  volatile int regenerate_interface_table;

  /* flag for JSON output format */
  u8 json_output;

  /* flag for interface event display */
  u8 interface_event_display;

  /* JSON tree used in composing dump api call results */
  vat_json_node_t json_tree;

  /* counters */
  u64 **simple_interface_counters;
  interface_counter_t **combined_interface_counters;
  ip4_fib_counter_t **ip4_fib_counters;
  u32 *ip4_fib_counters_vrf_id_by_index;
  ip6_fib_counter_t **ip6_fib_counters;
  u32 *ip6_fib_counters_vrf_id_by_index;
  ip4_nbr_counter_t **ip4_nbr_counters;
  ip6_nbr_counter_t **ip6_nbr_counters;

  /* Convenience */
  vlib_main_t *vlib_main;
} vat_main_t;

extern vat_main_t vat_main;

void vat_suspend (vlib_main_t * vm, f64 interval);
f64 vat_time_now (vat_main_t * vam);
void errmsg (char *fmt, ...);
void vat_api_hookup (vat_main_t * vam);
int api_sw_interface_dump (vat_main_t * vam);
void do_one_file (vat_main_t * vam);
int exec (vat_main_t * vam);

/* Plugin API library functions */
char *vat_plugin_path;
char *vat_plugin_name_filter;
void vat_plugin_api_reference (void);
uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
uword unformat_ip4_address (unformat_input_t * input, va_list * args);
uword unformat_ethernet_address (unformat_input_t * input, va_list * args);
uword unformat_ethernet_type_host_byte_order (unformat_input_t * input,
					      va_list * args);
uword unformat_ip6_address (unformat_input_t * input, va_list * args);
u8 *format_ip4_address (u8 * s, va_list * args);
u8 *format_ethernet_address (u8 * s, va_list * args);

#if VPP_API_TEST_BUILTIN
#define print api_cli_output
void api_cli_output (void *, const char *fmt, ...);
#else
#define print fformat_append_cr
void fformat_append_cr (FILE *, const char *fmt, ...);
#endif

#endif /* __included_vat_h__ */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */