From b538dd868665009f9a3737610177342f88e3ba80 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 21 May 2019 06:54:54 -0700 Subject: [PATCH] Punt: specify packets by IP protocol Type Change-Id: I0c2d6fccd95146e52bb88ca4a6e84554d5d6b2ed Signed-off-by: Neale Ranns --- src/vnet/ip/ip4.h | 1 + src/vnet/ip/ip4_forward.c | 14 +++- src/vnet/ip/ip6.h | 1 + src/vnet/ip/ip6_forward.c | 10 +++ src/vnet/ip/ip_types.api | 2 + src/vnet/ip/ip_types_api.c | 25 ++++--- src/vnet/ip/punt.api | 13 ++++ src/vnet/ip/punt.c | 132 +++++++++++++++++++++++++++++++----- src/vnet/ip/punt.h | 39 ++++++++++- src/vnet/ip/punt_api.c | 26 ++++++++ src/vnet/ip/punt_node.c | 57 +++++++++++++++- test/test_punt.py | 163 ++++++++++++++++++++++++++++++++++++++++++++- 12 files changed, 442 insertions(+), 41 deletions(-) diff --git a/src/vnet/ip/ip4.h b/src/vnet/ip/ip4.h index 5c9add4c796..9f25f43b98e 100644 --- a/src/vnet/ip/ip4.h +++ b/src/vnet/ip/ip4.h @@ -288,6 +288,7 @@ u16 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0, ip4_header_t * ip0); void ip4_register_protocol (u32 protocol, u32 node_index); +void ip4_unregister_protocol (u32 protocolx); serialize_function_t serialize_vnet_ip4_main, unserialize_vnet_ip4_main; diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index 9c5524f17a0..43213fe8ace 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -1679,6 +1679,16 @@ ip4_register_protocol (u32 protocol, u32 node_index) lm->local_next_by_ip_protocol[protocol] = vlib_node_add_next (vm, ip4_local_node.index, node_index); } + +void +ip4_unregister_protocol (u32 protocol) +{ + ip4_main_t *im = &ip4_main; + ip_lookup_main_t *lm = &im->lookup_main; + + ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol)); + lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT; +} #endif static clib_error_t * @@ -1697,8 +1707,8 @@ show_ip_local_command_fn (vlib_main_t * vm, u32 node_index = vlib_get_node (vm, ip4_local_node.index)-> next_nodes[lm->local_next_by_ip_protocol[i]]; - vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm, - node_index); + vlib_cli_output (vm, "%U: %U", format_ip_protocol, i, + format_vlib_node_name, vm, node_index); } } return 0; diff --git a/src/vnet/ip/ip6.h b/src/vnet/ip/ip6.h index e66bbdd0827..b511cccbaa7 100644 --- a/src/vnet/ip/ip6.h +++ b/src/vnet/ip/ip6.h @@ -388,6 +388,7 @@ u16 ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0, int *bogus_lengthp); void ip6_register_protocol (u32 protocol, u32 node_index); +void ip6_unregister_protocol (u32 protocol); void ip6_local_hop_by_hop_register_protocol (u32 protocol, u32 node_index); serialize_function_t serialize_vnet_ip6_main, unserialize_vnet_ip6_main; diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index 74f51fa912f..b6eae6e3811 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -1433,6 +1433,16 @@ ip6_register_protocol (u32 protocol, u32 node_index) vlib_node_add_next (vm, ip6_local_node.index, node_index); } +void +ip6_unregister_protocol (u32 protocol) +{ + ip6_main_t *im = &ip6_main; + ip_lookup_main_t *lm = &im->lookup_main; + + ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol)); + lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT; +} + clib_error_t * ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index, u8 refresh) diff --git a/src/vnet/ip/ip_types.api b/src/vnet/ip/ip_types.api index a9e66470665..4c685670d5e 100644 --- a/src/vnet/ip/ip_types.api +++ b/src/vnet/ip/ip_types.api @@ -25,6 +25,8 @@ enum address_family { enum ip_proto { IP_API_PROTO_TCP = 6, IP_API_PROTO_UDP = 17, + IP_API_PROTO_EIGRP = 88, + IP_API_PROTO_OSPF = 89, }; union address_union { diff --git a/src/vnet/ip/ip_types_api.c b/src/vnet/ip/ip_types_api.c index d84c1ff9126..fd8d24f36fe 100644 --- a/src/vnet/ip/ip_types_api.c +++ b/src/vnet/ip/ip_types_api.c @@ -65,16 +65,16 @@ ip_address_family_encode (ip_address_family_t af) int ip_proto_decode (int _ipp, ip_protocol_t * out) { - vl_api_ip_proto_t ipp = clib_host_to_net_u32 (_ipp); + ip_protocol_t ipp = clib_host_to_net_u32 (_ipp); switch (ipp) { - case IP_API_PROTO_TCP: - *out = IP_PROTOCOL_TCP; - return (0); - case IP_API_PROTO_UDP: - *out = IP_PROTOCOL_UDP; - return (0); +#define ip_protocol(n,s) \ + case IP_PROTOCOL_##s: \ + *out = IP_PROTOCOL_##s; \ + return (0); +#include "protocols.def" +#undef ip_protocol } return (-1); } @@ -84,12 +84,11 @@ ip_proto_encode (ip_protocol_t ipp) { switch (ipp) { - case IP_PROTOCOL_UDP: - return (clib_host_to_net_u32 (IP_API_PROTO_UDP)); - case IP_PROTOCOL_TCP: - return (clib_host_to_net_u32 (IP_API_PROTO_TCP)); - default: - break; +#define ip_protocol(n,s) \ + case IP_PROTOCOL_##s: \ + return (clib_host_to_net_u32 (IP_PROTOCOL_##s)); +#include "protocols.def" +#undef ip_protocol } ASSERT (0); diff --git a/src/vnet/ip/punt.api b/src/vnet/ip/punt.api index cedddc5601d..6cb27311726 100644 --- a/src/vnet/ip/punt.api +++ b/src/vnet/ip/punt.api @@ -22,6 +22,8 @@ enum punt_type { /* L4 (UDP) packets */ PUNT_API_TYPE_L4, + /* IP proto (i.e. OSPF, RIP, etc) packets */ + PUNT_API_TYPE_IP_PROTO, /* Exception packets handled by the VLIB punt infra */ PUNT_API_TYPE_EXCEPTION, }; @@ -38,6 +40,16 @@ typedef punt_l4 u16 port; }; +/** \brief Punt IP protocol traffic definition + @param af - Address Family, IPv4 or IPV6 + @param protocol - IP protocol to be punted +*/ +typedef punt_ip_proto +{ + vl_api_address_family_t af; + vl_api_ip_proto_t protocol; +}; + /** \brief The ID of the punt exception reason Dump all the reasons to obtain this */ @@ -52,6 +64,7 @@ union punt_union { vl_api_punt_exception_t exception; vl_api_punt_l4_t l4; + vl_api_punt_ip_proto_t ip_proto; }; /** \brief Full description of which packets are requested to be punted diff --git a/src/vnet/ip/punt.c b/src/vnet/ip/punt.c index d4d502887d7..296df59b615 100644 --- a/src/vnet/ip/punt.c +++ b/src/vnet/ip/punt.c @@ -74,6 +74,36 @@ punt_client_l4_db_remove (ip_address_family_t af, u16 port) return (index); } +static void +punt_client_ip_proto_db_add (ip_address_family_t af, + ip_protocol_t proto, u32 index) +{ + punt_main_t *pm = &punt_main; + + pm->db.clients_by_ip_proto = hash_set (pm->db.clients_by_ip_proto, + punt_client_ip_proto_mk_key (af, + proto), + index); +} + +static u32 +punt_client_ip_proto_db_remove (ip_address_family_t af, ip_protocol_t proto) +{ + punt_main_t *pm = &punt_main; + u32 key, index = ~0; + uword *p; + + key = punt_client_ip_proto_mk_key (af, proto); + p = hash_get (pm->db.clients_by_ip_proto, key); + + if (p) + index = p[0]; + + hash_unset (pm->db.clients_by_ip_proto, key); + + return (index); +} + static void punt_client_exception_db_add (vlib_punt_reason_t reason, u32 pci) { @@ -129,12 +159,6 @@ punt_socket_register_l4 (vlib_main_t * vm, if (port == (u16) ~ 0) return clib_error_return (0, "UDP port number required"); - if (strncmp (client_pathname, vnet_punt_get_server_pathname (), - UNIX_PATH_MAX) == 0) - return clib_error_return (0, - "Punt socket: Invalid client path: %s", - client_pathname); - c = punt_client_l4_get (af, port); if (NULL == c) @@ -159,6 +183,36 @@ punt_socket_register_l4 (vlib_main_t * vm, return (NULL); } +static clib_error_t * +punt_socket_register_ip_proto (vlib_main_t * vm, + ip_address_family_t af, + ip_protocol_t proto, char *client_pathname) +{ + punt_main_t *pm = &punt_main; + punt_client_t *c; + + c = punt_client_ip_proto_get (af, proto); + + if (NULL == c) + { + pool_get_zero (pm->punt_client_pool, c); + punt_client_ip_proto_db_add (af, proto, c - pm->punt_client_pool); + } + + memcpy (c->caddr.sun_path, client_pathname, sizeof (c->caddr.sun_path)); + c->caddr.sun_family = AF_UNIX; + c->reg.type = PUNT_TYPE_IP_PROTO; + c->reg.punt.ip_proto.protocol = proto; + c->reg.punt.ip_proto.af = af; + + if (af == AF_IP4) + ip4_register_protocol (proto, ip4_proto_punt_socket_node.index); + else + ip6_register_protocol (proto, ip6_proto_punt_socket_node.index); + + return (NULL); +} + static clib_error_t * punt_socket_register_exception (vlib_main_t * vm, vlib_punt_reason_t reason, @@ -202,6 +256,24 @@ punt_socket_unregister_l4 (ip_address_family_t af, return (NULL); } +static clib_error_t * +punt_socket_unregister_ip_proto (ip_address_family_t af, ip_protocol_t proto) +{ + u32 pci; + + if (af == AF_IP4) + ip4_unregister_protocol (proto); + else + ip6_unregister_protocol (proto); + + pci = punt_client_ip_proto_db_remove (af, proto); + + if (~0 != pci) + pool_put_index (punt_main.punt_client_pool, pci); + + return (NULL); +} + static clib_error_t * punt_socket_unregister_exception (vlib_punt_reason_t reason) { @@ -227,6 +299,12 @@ vnet_punt_socket_add (vlib_main_t * vm, u32 header_version, if (header_version != PUNT_PACKETDESC_VERSION) return clib_error_return (0, "Invalid packet descriptor version"); + if (strncmp (client_pathname, vnet_punt_get_server_pathname (), + UNIX_PATH_MAX) == 0) + return clib_error_return (0, + "Punt socket: Invalid client path: %s", + client_pathname); + /* Register client */ switch (pr->type) { @@ -235,6 +313,11 @@ vnet_punt_socket_add (vlib_main_t * vm, u32 header_version, pr->punt.l4.af, pr->punt.l4.protocol, pr->punt.l4.port, client_pathname)); + case PUNT_TYPE_IP_PROTO: + return (punt_socket_register_ip_proto (vm, + pr->punt.ip_proto.af, + pr->punt.ip_proto.protocol, + client_pathname)); case PUNT_TYPE_EXCEPTION: return (punt_socket_register_exception (vm, pr->punt.exception.reason, @@ -258,6 +341,9 @@ vnet_punt_socket_del (vlib_main_t * vm, const punt_reg_t * pr) return (punt_socket_unregister_l4 (pr->punt.l4.af, pr->punt.l4.protocol, pr->punt.l4.port)); + case PUNT_TYPE_IP_PROTO: + return (punt_socket_unregister_ip_proto (pr->punt.ip_proto.af, + pr->punt.ip_proto.protocol)); case PUNT_TYPE_EXCEPTION: return (punt_socket_unregister_exception (pr->punt.exception.reason)); } @@ -330,13 +416,6 @@ punt_l4_add_del (vlib_main_t * vm, } } -static clib_error_t * -punt_exception_add_del (vlib_main_t * vm, - vlib_punt_reason_t reason, bool is_add) -{ - return (NULL); -} - clib_error_t * vnet_punt_add_del (vlib_main_t * vm, const punt_reg_t * pr, bool is_add) { @@ -346,7 +425,8 @@ vnet_punt_add_del (vlib_main_t * vm, const punt_reg_t * pr, bool is_add) return (punt_l4_add_del (vm, pr->punt.l4.af, pr->punt.l4.protocol, pr->punt.l4.port, is_add)); case PUNT_TYPE_EXCEPTION: - return (punt_exception_add_del (vm, pr->punt.exception.reason, is_add)); + case PUNT_TYPE_IP_PROTO: + break; } return (clib_error_return (0, "Unsupported punt type: %d", pr->type)); @@ -560,11 +640,22 @@ punt_client_walk (punt_type_t pt, punt_client_walk_cb_t cb, void *ctx) { case PUNT_TYPE_L4: { - u32 pci; - u16 port; + u32 pci, key; /* *INDENT-OFF* */ - hash_foreach(port, pci, pm->db.clients_by_l4_port, + hash_foreach(key, pci, pm->db.clients_by_l4_port, + ({ + cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx); + })); + /* *INDENT-ON* */ + break; + } + case PUNT_TYPE_IP_PROTO: + { + u32 pci, key; + + /* *INDENT-OFF* */ + hash_foreach(key, pci, pm->db.clients_by_ip_proto, ({ cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx); })); @@ -601,6 +692,11 @@ format_punt_client (u8 * s, va_list * args) format_ip_protocol, pc->reg.punt.l4.protocol, pc->reg.punt.l4.port); break; + case PUNT_TYPE_IP_PROTO: + s = format (s, "%U %U", + format_ip_address_family, pc->reg.punt.ip_proto.af, + format_ip_protocol, pc->reg.punt.ip_proto.protocol); + break; case PUNT_TYPE_EXCEPTION: s = format (s, " %U", format_vlib_punt_reason, pc->reg.punt.exception.reason); @@ -635,6 +731,8 @@ punt_socket_show_cmd (vlib_main_t * vm, pt = PUNT_TYPE_EXCEPTION; else if (unformat (input, "l4")) pt = PUNT_TYPE_L4; + else if (unformat (input, "ip")) + pt = PUNT_TYPE_IP_PROTO; else { error = clib_error_return (0, "parse error: '%U'", diff --git a/src/vnet/ip/punt.h b/src/vnet/ip/punt.h index a77e6330813..8835f3eb9d9 100644 --- a/src/vnet/ip/punt.h +++ b/src/vnet/ip/punt.h @@ -24,9 +24,10 @@ #include #include -#define foreach_punt_type \ - _(L4, "l4") \ - _(EXCEPTION, "exception") +#define foreach_punt_type \ + _(L4, "l4") \ + _(EXCEPTION, "exception") \ + _(IP_PROTO, "ip-proto") typedef enum punt_type_t_ { @@ -42,6 +43,12 @@ typedef struct punt_l4_t_ u16 port; } punt_l4_t; +typedef struct punt_ip_proto_t_ +{ + ip_address_family_t af; + ip_protocol_t protocol; +} punt_ip_proto_t; + typedef struct punt_exception_t_ { vlib_punt_reason_t reason; @@ -51,6 +58,7 @@ typedef struct punt_union_t_ { punt_exception_t exception; punt_l4_t l4; + punt_ip_proto_t ip_proto; } punt_union_t; typedef struct punt_reg_t_ @@ -100,6 +108,7 @@ typedef struct punt_client_db_t_ { void *clients_by_l4_port; u32 *clients_by_exception; + void *clients_by_ip_proto; } punt_client_db_t; typedef struct @@ -146,6 +155,28 @@ punt_client_l4_get (ip_address_family_t af, u16 port) return (NULL); } +static_always_inline u32 +punt_client_ip_proto_mk_key (ip_address_family_t af, ip_protocol_t proto) +{ + return (af << 16 | proto); +} + +static_always_inline punt_client_t * +punt_client_ip_proto_get (ip_address_family_t af, ip_protocol_t proto) +{ + punt_main_t *pm = &punt_main; + uword *p; + + p = + hash_get (pm->db.clients_by_ip_proto, + punt_client_ip_proto_mk_key (af, proto)); + + if (p) + return (pool_elt_at_index (pm->punt_client_pool, p[0])); + + return (NULL); +} + static_always_inline punt_client_t * punt_client_exception_get (vlib_punt_reason_t reason) { @@ -167,6 +198,8 @@ extern vlib_node_registration_t udp4_punt_node; extern vlib_node_registration_t udp6_punt_node; extern vlib_node_registration_t udp4_punt_socket_node; extern vlib_node_registration_t udp6_punt_socket_node; +extern vlib_node_registration_t ip4_proto_punt_socket_node; +extern vlib_node_registration_t ip6_proto_punt_socket_node; extern vlib_node_registration_t punt_socket_rx_node; #endif diff --git a/src/vnet/ip/punt_api.c b/src/vnet/ip/punt_api.c index 95fff714b46..b356886a56f 100644 --- a/src/vnet/ip/punt_api.c +++ b/src/vnet/ip/punt_api.c @@ -95,6 +95,18 @@ vl_api_punt_l4_decode (const vl_api_punt_l4_t * in, punt_l4_t * out) return (rv); } +static int +vl_api_punt_ip_proto_decode (const vl_api_punt_ip_proto_t * in, + punt_ip_proto_t * out) +{ + int rv; + + rv = ip_address_family_decode (in->af, &out->af); + rv += ip_proto_decode (in->protocol, &out->protocol); + + return (rv); +} + static int vl_api_punt_exception_decode (const vl_api_punt_exception_t * in, punt_exception_t * out) @@ -124,6 +136,9 @@ vl_api_punt_decode (const vl_api_punt_t * in, punt_reg_t * out) case PUNT_TYPE_EXCEPTION: return (vl_api_punt_exception_decode (&in->punt.exception, &out->punt.exception)); + case PUNT_TYPE_IP_PROTO: + return (vl_api_punt_ip_proto_decode (&in->punt.ip_proto, + &out->punt.ip_proto)); } return (-1); @@ -137,6 +152,14 @@ vl_api_punt_l4_encode (const punt_l4_t * in, vl_api_punt_l4_t * out) out->port = clib_net_to_host_u16 (in->port); } +static void +vl_api_punt_ip_proto_encode (const punt_ip_proto_t * in, + vl_api_punt_ip_proto_t * out) +{ + out->af = ip_address_family_encode (in->af); + out->protocol = ip_proto_encode (in->protocol); +} + static void vl_api_punt_exception_encode (const punt_exception_t * in, vl_api_punt_exception_t * out) @@ -154,6 +177,9 @@ vl_api_punt_encode (const punt_reg_t * in, vl_api_punt_t * out) case PUNT_TYPE_L4: vl_api_punt_l4_encode (&in->punt.l4, &out->punt.l4); break; + case PUNT_TYPE_IP_PROTO: + vl_api_punt_ip_proto_encode (&in->punt.ip_proto, &out->punt.ip_proto); + break; case PUNT_TYPE_EXCEPTION: vl_api_punt_exception_encode (&in->punt.exception, &out->punt.exception); diff --git a/src/vnet/ip/punt_node.c b/src/vnet/ip/punt_node.c index 53c8199342b..67f97431c19 100644 --- a/src/vnet/ip/punt_node.c +++ b/src/vnet/ip/punt_node.c @@ -286,13 +286,29 @@ punt_socket_inline (vlib_main_t * vm, udp = (udp_header_t *) (ip + 1); } - u16 port = clib_net_to_host_u16 (udp->dst_port); - /* * Find registerered client * If no registered client, drop packet and count */ - c = punt_client_l4_get (af, port); + c = punt_client_l4_get (af, clib_net_to_host_u16 (udp->dst_port)); + } + else if (PUNT_TYPE_IP_PROTO == pt) + { + /* Reverse UDP Punt advance */ + ip_protocol_t proto; + + if (AF_IP4 == af) + { + ip4_header_t *ip = vlib_buffer_get_current (b); + proto = ip->protocol; + } + else + { + ip6_header_t *ip = vlib_buffer_get_current (b); + proto = ip->protocol; + } + + c = punt_client_ip_proto_get (af, proto); } else if (PUNT_TYPE_EXCEPTION == pt) { @@ -390,6 +406,22 @@ udp6_punt_socket (vlib_main_t * vm, return punt_socket_inline (vm, node, from_frame, PUNT_TYPE_L4, AF_IP6); } +static uword +ip4_proto_punt_socket (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * from_frame) +{ + return punt_socket_inline (vm, node, from_frame, + PUNT_TYPE_IP_PROTO, AF_IP4); +} + +static uword +ip6_proto_punt_socket (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * from_frame) +{ + return punt_socket_inline (vm, node, from_frame, + PUNT_TYPE_IP_PROTO, AF_IP6); +} + static uword exception_punt_socket (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) @@ -419,6 +451,25 @@ VLIB_REGISTER_NODE (udp6_punt_socket_node) = { .n_errors = PUNT_N_ERROR, .error_strings = punt_error_strings, }; +VLIB_REGISTER_NODE (ip4_proto_punt_socket_node) = { + .function = ip4_proto_punt_socket, + .name = "ip4-proto-punt-socket", + .format_trace = format_udp_punt_trace, + .flags = VLIB_NODE_FLAG_IS_DROP, + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), + .n_errors = PUNT_N_ERROR, + .error_strings = punt_error_strings, +}; +VLIB_REGISTER_NODE (ip6_proto_punt_socket_node) = { + .function = ip6_proto_punt_socket, + .name = "ip6-proto-punt-socket", + .format_trace = format_udp_punt_trace, + .flags = VLIB_NODE_FLAG_IS_DROP, + .vector_size = sizeof (u32), + .n_errors = PUNT_N_ERROR, + .error_strings = punt_error_strings, +}; VLIB_REGISTER_NODE (exception_punt_socket_node) = { .function = exception_punt_socket, .name = "exception-punt-socket", diff --git a/test/test_punt.py b/test/test_punt.py index 28c17daa08a..598f140547b 100644 --- a/test/test_punt.py +++ b/test/test_punt.py @@ -22,6 +22,7 @@ from scapy.layers.inet import IP, UDP, ICMP from scapy.layers.ipsec import ESP import scapy.layers.inet6 as inet6 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach +from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello import six from framework import VppTestCase, VppTestRunner @@ -130,6 +131,13 @@ class TestPuntSocket(VppTestCase): self.assertEqual(vpr.punt.punt.exception.id, pr['punt']['exception']['id']) + def verify_ip_proto(self, pr, vpr): + self.assertEqual(vpr.punt.type, pr['type']) + self.assertEqual(vpr.punt.punt.ip_proto.af, + pr['punt']['ip_proto']['af']) + self.assertEqual(vpr.punt.punt.ip_proto.protocol, + pr['punt']['ip_proto']['protocol']) + def verify_udp_pkts(self, rxs, n_rx, port): n_match = 0 for rx in rxs: @@ -182,7 +190,7 @@ def mk_vpp_cfg6(): class TestIP4PuntSocket(TestPuntSocket): - """ Punt Socket for IPv4 """ + """ Punt Socket for IPv4 UDP """ @classmethod def setUpClass(cls): @@ -409,7 +417,7 @@ class TestIP4PuntSocket(TestPuntSocket): class TestIP6PuntSocket(TestPuntSocket): - """ Punt Socket for IPv6""" + """ Punt Socket for IPv6 UDP """ @classmethod def setUpClass(cls): @@ -850,8 +858,157 @@ class TestExceptionPuntSocket(TestPuntSocket): self.vapi.punt_socket_deregister(cfg['vpp']) +class TestIpProtoPuntSocket(TestPuntSocket): + """ Punt Socket for IP packets """ + + @classmethod + def setUpClass(cls): + super(TestIpProtoPuntSocket, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestIpProtoPuntSocket, cls).tearDownClass() + + def setUp(self): + super(TestIpProtoPuntSocket, self).setUp() + + for i in self.pg_interfaces: + i.config_ip4() + i.resolve_arp() + + def tearDown(self): + super(TestIpProtoPuntSocket, self).tearDown() + for i in self.pg_interfaces: + i.unconfig_ip4() + i.admin_down() + + def test_registration(self): + """ Punt socket registration/deregistration""" + + af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4 + pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO + proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF + proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP + + punts = self.vapi.punt_socket_dump(type=pt_ip) + self.assertEqual(len(punts), 0) + + # + # configure a punt socket + # + punt_ospf = { + 'type': pt_ip, + 'punt': { + 'ip_proto': { + 'af': af_ip4, + 'protocol': proto_ospf + } + } + } + punt_eigrp = { + 'type': pt_ip, + 'punt': { + 'ip_proto': { + 'af': af_ip4, + 'protocol': proto_eigrp + } + } + } + + self.vapi.punt_socket_register(punt_ospf, + b"%s/socket_punt_1" % + six.ensure_binary(self.tempdir)) + self.vapi.punt_socket_register(punt_eigrp, + b"%s/socket_punt_2" % + six.ensure_binary(self.tempdir)) + self.logger.info(self.vapi.cli("sh punt sock reg ip")) + punts = self.vapi.punt_socket_dump(type=pt_ip) + self.assertEqual(len(punts), 2) + self.verify_ip_proto(punt_ospf, punts[0]) + self.verify_ip_proto(punt_eigrp, punts[1]) + + # + # deregister a punt socket + # + self.vapi.punt_socket_deregister(punt_ospf) + punts = self.vapi.punt_socket_dump(type=pt_ip) + self.assertEqual(len(punts), 1) + + # + # configure a punt socket again + # + self.vapi.punt_socket_register(punt_ospf, + b"%s/socket_punt_3" % + six.ensure_binary(self.tempdir)) + punts = self.vapi.punt_socket_dump(type=pt_ip) + self.assertEqual(len(punts), 2) + + self.logger.info(self.vapi.cli("sh punt sock reg exception")) + + # + # deregister all punt socket + # + self.vapi.punt_socket_deregister(punt_eigrp) + self.vapi.punt_socket_deregister(punt_ospf) + punts = self.vapi.punt_socket_dump(type=pt_ip) + self.assertEqual(len(punts), 0) + + def verify_ospf_pkts(self, rxs, n_sent): + self.assertEqual(len(rxs), n_sent) + for rx in rxs: + self.assertTrue(rx.haslayer(OSPF_Hdr)) + + def test_traffic(self): + """ Punt socket traffic """ + + af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4 + pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO + proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF + + # + # configure a punt socket to capture OSPF packets + # + punt_ospf = { + 'type': pt_ip, + 'punt': { + 'ip_proto': { + 'af': af_ip4, + 'protocol': proto_ospf + } + } + } + + # + # create packet streams and configure a punt sockets + # + pkt = (Ether(src=self.pg0.remote_mac, + dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + OSPF_Hdr() / + OSPFv3_Hello()) + pkts = pkt * 7 + + sock = self.socket_client_create(b"%s/socket_1" % ( + six.ensure_binary(self.tempdir))) + self.vapi.punt_socket_register( + punt_ospf, + b"%s/socket_1" % (six.ensure_binary(self.tempdir))) + + # + # send packets for each SPI we expect to be punted + # + self.send_and_assert_no_replies(self.pg0, pkts) + + # + # verify the punted packets arrived on the associated socket + # + rx = sock.close() + self.verify_ospf_pkts(rx, len(pkts)) + self.vapi.punt_socket_deregister(punt_ospf) + + class TestPunt(VppTestCase): - """ Punt Test Case """ + """ Exception Punt Test Case """ @classmethod def setUpClass(cls): -- 2.16.6