diff options
Diffstat (limited to 'src/plugins/nat/pnat')
-rw-r--r-- | src/plugins/nat/pnat/pnat.api | 18 | ||||
-rw-r--r-- | src/plugins/nat/pnat/pnat.c | 4 | ||||
-rw-r--r-- | src/plugins/nat/pnat/pnat.md | 37 | ||||
-rw-r--r-- | src/plugins/nat/pnat/pnat.rst | 45 | ||||
-rw-r--r-- | src/plugins/nat/pnat/pnat_api.c | 36 | ||||
-rw-r--r-- | src/plugins/nat/pnat/pnat_cli.c | 6 | ||||
-rw-r--r-- | src/plugins/nat/pnat/pnat_node.h | 1 | ||||
-rw-r--r-- | src/plugins/nat/pnat/tests/pnat_test.c | 8 | ||||
-rw-r--r-- | src/plugins/nat/pnat/tests/pnat_test_stubs.h | 6 | ||||
-rwxr-xr-x | src/plugins/nat/pnat/tests/test_genpackets.py | 30 |
10 files changed, 116 insertions, 75 deletions
diff --git a/src/plugins/nat/pnat/pnat.api b/src/plugins/nat/pnat/pnat.api index b6632159d7c..de555c41412 100644 --- a/src/plugins/nat/pnat/pnat.api +++ b/src/plugins/nat/pnat/pnat.api @@ -26,6 +26,7 @@ enum pnat_mask PNAT_DPORT = 0x8, PNAT_COPY_BYTE = 0x10, PNAT_CLEAR_BYTE = 0x20, + PNAT_PROTO = 0x40, }; enum pnat_attachment_point @@ -65,6 +66,7 @@ autoendian define pnat_binding_add vl_api_pnat_rewrite_tuple_t rewrite; }; + autoendian define pnat_binding_add_reply { u32 context; @@ -72,6 +74,22 @@ autoendian define pnat_binding_add_reply u32 binding_index; }; +autoendian define pnat_binding_add_v2 +{ + u32 client_index; + u32 context; + vl_api_pnat_match_tuple_t match; + vl_api_pnat_rewrite_tuple_t rewrite; +}; + + +autoendian define pnat_binding_add_v2_reply +{ + u32 context; + i32 retval; + u32 binding_index; +}; + autoendian autoreply define pnat_binding_del { u32 client_index; diff --git a/src/plugins/nat/pnat/pnat.c b/src/plugins/nat/pnat/pnat.c index 547b063f286..2b4a6b49e96 100644 --- a/src/plugins/nat/pnat/pnat.c +++ b/src/plugins/nat/pnat/pnat.c @@ -56,7 +56,9 @@ static pnat_mask_fast_t pnat_mask2fast(pnat_mask_t lookup_mask) { m.as_u64[0] = 0xffffffff00000000; if (lookup_mask & PNAT_DA) m.as_u64[0] |= 0x00000000ffffffff; - m.as_u64[1] = 0xffffffff00000000; + m.as_u64[1] = 0x00ffffff00000000; + if (lookup_mask & PNAT_PROTO) + m.as_u64[1] |= 0xff00000000000000; if (lookup_mask & PNAT_SPORT) m.as_u64[1] |= 0x00000000ffff0000; if (lookup_mask & PNAT_DPORT) diff --git a/src/plugins/nat/pnat/pnat.md b/src/plugins/nat/pnat/pnat.md deleted file mode 100644 index 1e6bc130848..00000000000 --- a/src/plugins/nat/pnat/pnat.md +++ /dev/null @@ -1,37 +0,0 @@ -# PNAT: 1:1 match and rewrite programmable NAT {#pnat_doc} - -PNAT is a stateless statically configured, match and rewrite plugin. -It uses a set of match and rewrite rules that are applied on the IP -input and output feature paths. A PNAT rule is unidirectional. - -The match is done using up to a 6-tuple; IP source and destination address, -IP protocol, transport layer source and destination ports, and FIB table / interface index. - -While multiple match/rewrite rules can be applied to an interface (per direction), the match -pattern must be the same across all rules on that interface/direction. - -If required in the future, matching could be done using the general classifier, allowing matching -on any protocol field, as well having an ordered set of match patterns. - -If the packet does not match, it will by default be passed to the next graph node in the feature chain. -If desired a different miss behaviour could be implemented, e.g. similarly to dynamic NAT, the packet punted to a slow path. - -## Rewrite instructions - -``` c -typedef enum { - PNAT_INSTR_NONE = 1 << 0, - PNAT_INSTR_SOURCE_ADDRESS = 1 << 1, - PNAT_INSTR_SOURCE_PORT = 1 << 2, - PNAT_INSTR_DESTINATION_ADDRESS = 1 << 3, - PNAT_INSTR_DESTINATION_PORT = 1 << 4, -} pnat_instructions_t; -``` - -These are the supported rewrite instructions. -The IP checksum and the TCP/UDP checksum are incrementally updated as required. - -There are only a few "sanity checks" on the rewrites. For example, the rewrite in the outbound direction -is applied on the ip-output feature chain. If one were to rewrite the IP destination address, the routing -decision and determination of the next-hop has already been done, and the packet would still be forwarded -to the original next-hop. diff --git a/src/plugins/nat/pnat/pnat.rst b/src/plugins/nat/pnat/pnat.rst new file mode 100644 index 00000000000..5cac047a236 --- /dev/null +++ b/src/plugins/nat/pnat/pnat.rst @@ -0,0 +1,45 @@ +PNAT 1:1 match & rewrite NAT +============================ + +PNAT is a stateless statically configured, match and rewrite plugin. It +uses a set of match and rewrite rules that are applied on the IP input +and output feature paths. A PNAT rule is unidirectional. + +The match is done using up to a 6-tuple; IP source and destination +address, IP protocol, transport layer source and destination ports, and +FIB table / interface index. + +While multiple match/rewrite rules can be applied to an interface (per +direction), the match pattern must be the same across all rules on that +interface/direction. + +If required in the future, matching could be done using the general +classifier, allowing matching on any protocol field, as well having an +ordered set of match patterns. + +If the packet does not match, it will by default be passed to the next +graph node in the feature chain. If desired a different miss behaviour +could be implemented, e.g. similarly to dynamic NAT, the packet punted +to a slow path. + +Rewrite instructions +-------------------- + +.. code:: c + + typedef enum { + PNAT_INSTR_NONE = 1 << 0, + PNAT_INSTR_SOURCE_ADDRESS = 1 << 1, + PNAT_INSTR_SOURCE_PORT = 1 << 2, + PNAT_INSTR_DESTINATION_ADDRESS = 1 << 3, + PNAT_INSTR_DESTINATION_PORT = 1 << 4, + } pnat_instructions_t; + +These are the supported rewrite instructions. The IP checksum and the +TCP/UDP checksum are incrementally updated as required. + +There are only a few “sanity checks” on the rewrites. For example, the +rewrite in the outbound direction is applied on the ip-output feature +chain. If one were to rewrite the IP destination address, the routing +decision and determination of the next-hop has already been done, and +the packet would still be forwarded to the original next-hop. diff --git a/src/plugins/nat/pnat/pnat_api.c b/src/plugins/nat/pnat/pnat_api.c index eaefbaf4738..a4e7ff192bf 100644 --- a/src/plugins/nat/pnat/pnat_api.c +++ b/src/plugins/nat/pnat/pnat_api.c @@ -13,6 +13,7 @@ * limitations under the License. */ #include "pnat.h" +#include <vnet/vnet.h> #include <pnat/pnat.api_enum.h> #include <pnat/pnat.api_types.h> #include <vlibmemory/api.h> @@ -22,6 +23,7 @@ #include <vnet/ip/reass/ip4_sv_reass.h> #include <vnet/ip/reass/ip6_full_reass.h> #include <vnet/ip/reass/ip6_sv_reass.h> +#include <vpp/app/version.h> /* * This file contains the API handlers for the pnat.api @@ -34,22 +36,33 @@ static void vl_api_pnat_binding_add_t_handler(vl_api_pnat_binding_add_t *mp) { pnat_main_t *pm = &pnat_main; vl_api_pnat_binding_add_reply_t *rmp; u32 binding_index; + + // for backward compatibility + if (mp->match.proto == 0) + mp->match.mask |= PNAT_PROTO; + int rv = pnat_binding_add(&mp->match, &mp->rewrite, &binding_index); REPLY_MACRO2_END(VL_API_PNAT_BINDING_ADD_REPLY, ({ rmp->binding_index = binding_index; })); } static void +vl_api_pnat_binding_add_v2_t_handler(vl_api_pnat_binding_add_t *mp) { + pnat_main_t *pm = &pnat_main; + vl_api_pnat_binding_add_reply_t *rmp; + u32 binding_index; + int rv = pnat_binding_add(&mp->match, &mp->rewrite, &binding_index); + REPLY_MACRO2_END(VL_API_PNAT_BINDING_ADD_V2_REPLY, + ({ rmp->binding_index = binding_index; })); +} + +static void vl_api_pnat_binding_attach_t_handler(vl_api_pnat_binding_attach_t *mp) { pnat_main_t *pm = &pnat_main; vl_api_pnat_binding_attach_reply_t *rmp; int rv; - /* Ensure that the interface exists */ - if (!vnet_sw_if_index_is_api_valid(mp->sw_if_index)) { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto bad_sw_if_index; - } + VALIDATE_SW_IF_INDEX_END(mp); rv = pnat_binding_attach(mp->sw_if_index, mp->attachment, mp->binding_index); @@ -64,11 +77,7 @@ vl_api_pnat_binding_detach_t_handler(vl_api_pnat_binding_detach_t *mp) { vl_api_pnat_binding_detach_reply_t *rmp; int rv; - /* Ensure that the interface exists */ - if (!vnet_sw_if_index_is_api_valid(mp->sw_if_index)) { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto bad_sw_if_index; - } + VALIDATE_SW_IF_INDEX_END(mp); rv = pnat_binding_detach(mp->sw_if_index, mp->attachment, mp->binding_index); @@ -107,7 +116,8 @@ static void send_bindings_details(u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_pnat_bindings_details_t_endian(rmp); + vl_api_pnat_bindings_details_t_endian( + rmp, 1 /* to network */); rmp->_vl_msg_id = htons(rmp->_vl_msg_id); rmp->context = htonl(rmp->context); })); @@ -149,7 +159,7 @@ static void send_interfaces_details(u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_pnat_interfaces_details_t_endian(rmp); + vl_api_pnat_interfaces_details_t_endian(rmp, 1 /* to network */); rmp->_vl_msg_id = htons(rmp->_vl_msg_id); rmp->context = htonl(rmp->context); })); @@ -193,7 +203,7 @@ clib_error_t *pnat_plugin_api_hookup(vlib_main_t *vm) { */ #include <vnet/plugin/plugin.h> VLIB_PLUGIN_REGISTER() = { - .version = "0.0.1", + .version = VPP_BUILD_VER, .description = "Policy 1:1 NAT", }; diff --git a/src/plugins/nat/pnat/pnat_cli.c b/src/plugins/nat/pnat/pnat_cli.c index 082f0778acb..ce9beee540d 100644 --- a/src/plugins/nat/pnat/pnat_cli.c +++ b/src/plugins/nat/pnat/pnat_cli.c @@ -122,6 +122,8 @@ uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) { t->mask |= PNAT_SA; else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst)) t->mask |= PNAT_DA; + else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto)) + t->mask |= PNAT_PROTO; else if (unformat(input, "sport %d", &sport)) { if (sport == 0 || sport > 65535) return 0; @@ -132,9 +134,7 @@ uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) { return 0; t->mask |= PNAT_DPORT; t->dport = dport; - } else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto)) - ; - else + } else break; } return 1; diff --git a/src/plugins/nat/pnat/pnat_node.h b/src/plugins/nat/pnat/pnat_node.h index 595189c2efb..f1afb450934 100644 --- a/src/plugins/nat/pnat/pnat_node.h +++ b/src/plugins/nat/pnat/pnat_node.h @@ -20,6 +20,7 @@ #include <pnat/pnat.api_enum.h> #include <vnet/feature/feature.h> #include <vnet/udp/udp_packet.h> +#include <vnet/tcp/tcp_packet.h> #include <vnet/ip/format.h> /* PNAT next-nodes */ diff --git a/src/plugins/nat/pnat/tests/pnat_test.c b/src/plugins/nat/pnat/tests/pnat_test.c index e7d946941b9..f515dd6d376 100644 --- a/src/plugins/nat/pnat/tests/pnat_test.c +++ b/src/plugins/nat/pnat/tests/pnat_test.c @@ -25,6 +25,11 @@ #include <vnet/fib/ip4_fib.h> #include "../pnat.h" #include <pnat/pnat.api_enum.h> /* For error counters */ +#ifdef __FreeBSD__ +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> +#endif /* __FreeBSD__ */ #include <arpa/inet.h> #include "pnat_test_stubs.h" @@ -569,7 +574,8 @@ int main(int argc, char **argv) { ip_checksum_init(vm); - u32 node_index = vlib_register_node(vm, &pnat_input_node); + u32 node_index = + vlib_register_node(vm, &pnat_input_node, "%s", pnat_input_node.name); node = vlib_node_get_runtime(vm, node_index); assert(node); diff --git a/src/plugins/nat/pnat/tests/pnat_test_stubs.h b/src/plugins/nat/pnat/tests/pnat_test_stubs.h index bfe1838ffa4..2dc59ac8586 100644 --- a/src/plugins/nat/pnat/tests/pnat_test_stubs.h +++ b/src/plugins/nat/pnat/tests/pnat_test_stubs.h @@ -19,12 +19,6 @@ void os_panic(void) {} void os_exit(int code) {} u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index) { return 0; } -#include <vpp/stats/stat_segment.h> -clib_error_t *stat_segment_register_gauge(u8 *names, - stat_segment_update_fn update_fn, - u32 index) { - return 0; -}; #include <vnet/feature/feature.h> vnet_feature_main_t feature_main; void classify_get_trace_chain(void){}; diff --git a/src/plugins/nat/pnat/tests/test_genpackets.py b/src/plugins/nat/pnat/tests/test_genpackets.py index 9d32d3e3656..40867317078 100755 --- a/src/plugins/nat/pnat/tests/test_genpackets.py +++ b/src/plugins/nat/pnat/tests/test_genpackets.py @@ -6,33 +6,35 @@ from importlib.machinery import SourceFileLoader from scapy.all import * from scapy.contrib.geneve import GENEVE + def hexstring(p): s = bytes(p.__class__(p)) return ",".join("0x{:02x}".format(c) for c in s) + def output_test(filename, tests): (name, ext) = os.path.basename(filename).split(".") - print('/* DO NOT EDIT: automatically generated by test_genpackets.py */') - print('/* clang-format off */') - print('test_t tests_{}[] = {{'.format(name)) + print("/* DO NOT EDIT: automatically generated by test_genpackets.py */") + print("/* clang-format off */") + print("test_t tests_{}[] = {{".format(name)) for t in tests: - print(' {') + print(" {") print(' .name = "{}",'.format(t[0])) - print(' .nsend = {},'.format(len(t[1]))) - print(' .send = (char []){{{}}},'.format(hexstring(t[1]))) - print(' .nexpect = {},'.format(len(t[2]))) - print(' .expect = (char []){{{}}},'.format(hexstring(t[2]))) - print(' .expect_next_index = {}'.format(t[3])) - print(' },') - print('};') - print('/* clang-format on */') + print(" .nsend = {},".format(len(t[1]))) + print(" .send = (char []){{{}}},".format(hexstring(t[1]))) + print(" .nexpect = {},".format(len(t[2]))) + print(" .expect = (char []){{{}}},".format(hexstring(t[2]))) + print(" .expect_next_index = {}".format(t[3])) + print(" },") + print("};") + print("/* clang-format on */") + # Read tests from file for filename in sys.argv[1:]: with open(filename) as f: - content = f.read().replace('\n', '') + content = f.read().replace("\n", "") tests = eval(content) output_test(filename, tests) - |