From 947ea6222dad1ef04595c34273e9231395aef443 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 7 Jun 2018 23:48:20 -0700 Subject: IGMP improvements - Enable/Disable an interface for IGMP - improve logging - refactor common code - no orphaned timers - IGMP state changes in main thread only - Large groups split over multiple state-change reports - SSM range configuration API. - more tests Change-Id: If5674f1044e7e97274a711f47807c9ba689d7b9a Signed-off-by: Neale Ranns --- src/vnet/ip/igmp_packet.h | 88 +++++++++++++++++++++++++++++-------- src/vnet/ip/ip.api | 1 + src/vnet/ip/ip4_error.h | 2 +- src/vnet/ip/ip_types.api | 6 +++ src/vnet/ip/ip_types_api.c | 105 +++++++++++++++++++++++++++++++++++++++++++++ src/vnet/ip/ip_types_api.h | 50 +++++++++++++++++++++ 6 files changed, 234 insertions(+), 18 deletions(-) create mode 100644 src/vnet/ip/ip_types_api.c create mode 100644 src/vnet/ip/ip_types_api.h (limited to 'src/vnet/ip') diff --git a/src/vnet/ip/igmp_packet.h b/src/vnet/ip/igmp_packet.h index a8e9db6d9ab..cd4a40d77ff 100644 --- a/src/vnet/ip/igmp_packet.h +++ b/src/vnet/ip/igmp_packet.h @@ -63,32 +63,46 @@ typedef enum #define _(n,f) IGMP_TYPE_##f = n, foreach_igmp_type #undef _ -} igmp_type_t; +} __attribute__ ((packed)) igmp_type_t; typedef struct { - igmp_type_t type:8; + igmp_type_t type; u8 code; u16 checksum; } igmp_header_t; -typedef struct +/** + * Calculate the maximum response time allowed from the header. + * - RFC 3367 Section 4.1.1 + */ +always_inline f64 +igmp_header_get_max_resp_time (const igmp_header_t * header) { - /* membership_query, version <= 2 reports. */ - igmp_header_t header; + f64 qqi; - /* Multicast destination address. */ - ip4_address_t dst; -} igmp_message_t; + if (header->code < 128) + qqi = header->code; + else + { + u8 mant = header->code << 4; + u8 exp = (header->code & 0x7) << 1; + + qqi = ((mant | 0x10) << (exp + 3)); + } + + /* Querier's Query Interval (QQI), is represented in units of seconds */ + return (qqi / 10); +} typedef struct { /* type 0x11 (IGMPv3) */ igmp_header_t header; - ip4_address_t dst; + ip4_address_t group_address; /* Reserved, Suppress Router-Side Processing flag and Querier's Robustness Variable RRRRSQQQ. */ @@ -101,11 +115,25 @@ typedef struct ip4_address_t src_addresses[0]; } igmp_membership_query_v3_t; +always_inline u32 +igmp_membership_query_v3_length (const igmp_membership_query_v3_t * q) +{ + return (sizeof (*q) + + (sizeof (ip4_address_t) * + clib_net_to_host_u16 (q->n_src_addresses))); +} + +always_inline int +igmp_membership_query_v3_is_geeral (const igmp_membership_query_v3_t * q) +{ + return (0 == q->group_address.as_u32); +} + #define foreach_igmp_membership_group_v3_type \ - _ (1, mode_is_filter_include) \ - _ (2, mode_is_filter_exclude) \ - _ (3, change_to_filter_include) \ - _ (4, change_to_filter_exclude) \ + _ (1, mode_is_include) \ + _ (2, mode_is_exclude) \ + _ (3, change_to_include) \ + _ (4, change_to_exclude) \ _ (5, allow_new_sources) \ _ (6, block_old_sources) @@ -114,11 +142,11 @@ typedef enum #define _(n,f) IGMP_MEMBERSHIP_GROUP_##f = n, foreach_igmp_membership_group_v3_type #undef _ -} igmp_membership_group_v3_type_t; +} __attribute__ ((packed)) igmp_membership_group_v3_type_t; typedef struct { - igmp_membership_group_v3_type_t type:8; + igmp_membership_group_v3_type_t type; /* Number of 32 bit words of aux data after source addresses. */ u8 n_aux_u32s; @@ -126,12 +154,20 @@ typedef struct /* Number of source addresses that follow. */ u16 n_src_addresses; - /* Destination multicast address. */ - ip4_address_t dst_address; + /* Destination multicast group address. */ + ip4_address_t group_address; ip4_address_t src_addresses[0]; } igmp_membership_group_v3_t; +always_inline u32 +igmp_membership_group_v3_length (const igmp_membership_group_v3_t * g) +{ + return (sizeof (*g) + + (sizeof (ip4_address_t) * + clib_net_to_host_u16 (g->n_src_addresses))); +} + always_inline igmp_membership_group_v3_t * igmp_membership_group_v3_next (igmp_membership_group_v3_t * g) { @@ -153,6 +189,24 @@ typedef struct igmp_membership_group_v3_t groups[0]; } igmp_membership_report_v3_t; +always_inline u32 +igmp_membership_report_v3_length (const igmp_membership_report_v3_t * r) +{ + const igmp_membership_group_v3_t *g; + u32 len, ii, glen; + + len = sizeof (igmp_membership_report_v3_t); + g = r->groups; + + for (ii = 0; ii < clib_net_to_host_u16 (r->n_groups); ii++) + { + glen = igmp_membership_group_v3_length (g); + g = (const igmp_membership_group_v3_t *) (((u8 *) g) + glen); + len += glen; + } + return (len); +} + /* IP6 flavor of IGMP is called MLD which is embedded in ICMP6. */ typedef struct { diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api index 228e59158ff..4811a349d38 100644 --- a/src/vnet/ip/ip.api +++ b/src/vnet/ip/ip.api @@ -20,6 +20,7 @@ */ option version = "1.3.0"; +import "vnet/ip/ip_types.api"; import "vnet/fib/fib_types.api"; /** \brief Add / del table request diff --git a/src/vnet/ip/ip4_error.h b/src/vnet/ip/ip4_error.h index fa93e8673e5..52c43adb12c 100644 --- a/src/vnet/ip/ip4_error.h +++ b/src/vnet/ip/ip4_error.h @@ -59,7 +59,7 @@ _ (SRC_LOOKUP_MISS, "ip4 source lookup miss") \ _ (DROP, "ip4 drop") \ _ (PUNT, "ip4 punt") \ - _ (SAME_INTERFACE, "ip4 egrees interface same as ingress") \ + _ (SAME_INTERFACE, "ip4 egress interface same as ingress") \ \ /* Errors signalled by ip4-local. */ \ _ (UNKNOWN_PROTOCOL, "unknown ip protocol") \ diff --git a/src/vnet/ip/ip_types.api b/src/vnet/ip/ip_types.api index ec6b9d0024c..72eadaf92df 100644 --- a/src/vnet/ip/ip_types.api +++ b/src/vnet/ip/ip_types.api @@ -1,3 +1,4 @@ +/* Hey Emacs use -*- mode: C -*- */ /* * Copyright (c) 2018 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,3 +36,8 @@ typedef address { vl_api_address_family_t af; vl_api_address_union_t un; }; + +typedef prefix { + vl_api_address_t address; + u8 address_length; +}; diff --git a/src/vnet/ip/ip_types_api.c b/src/vnet/ip/ip_types_api.c new file mode 100644 index 00000000000..7fa8e404c78 --- /dev/null +++ b/src/vnet/ip/ip_types_api.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2018 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. + */ + +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include +#undef vl_printfun + + +void +ip_address_decode (const vl_api_address_t * in, ip46_address_t * out) +{ + switch (in->af) + { + case ADDRESS_IP4: + memset (out, 0, sizeof (*out)); + clib_memcpy (&out->ip4, &in->un.ip4, sizeof (out->ip4)); + break; + case ADDRESS_IP6: + clib_memcpy (&out->ip6, &in->un.ip6, sizeof (out->ip6)); + break; + } +} + +void +ip_address_encode (const ip46_address_t * in, vl_api_address_t * out) +{ + if (ip46_address_is_ip4 (in)) + { + memset (out, 0, sizeof (*out)); + out->af = ADDRESS_IP4; + clib_memcpy (&out->un.ip4, &in->ip4, sizeof (out->un.ip4)); + } + else + { + out->af = ADDRESS_IP6; + clib_memcpy (&out->un.ip6, &in->ip6, sizeof (out->un.ip6)); + } +} + +void +ip_prefix_decode (const vl_api_prefix_t * in, fib_prefix_t * out) +{ + switch (in->address.af) + { + case ADDRESS_IP4: + out->fp_proto = FIB_PROTOCOL_IP4; + break; + case ADDRESS_IP6: + out->fp_proto = FIB_PROTOCOL_IP6; + break; + } + out->fp_len = in->address_length; + ip_address_decode (&in->address, &out->fp_addr); +} + +void +ip_prefix_encode (const fib_prefix_t * in, vl_api_prefix_t * out) +{ + switch (in->fp_proto) + { + case FIB_PROTOCOL_IP4: + out->address.af = ADDRESS_IP4; + break; + case FIB_PROTOCOL_IP6: + out->address.af = ADDRESS_IP6; + break; + case FIB_PROTOCOL_MPLS: + ASSERT (0); + break; + } + out->address_length = in->fp_len; + ip_address_encode (&in->fp_addr, &out->address); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/ip/ip_types_api.h b/src/vnet/ip/ip_types_api.h new file mode 100644 index 00000000000..2ad59ae438e --- /dev/null +++ b/src/vnet/ip/ip_types_api.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 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 __IP_TYPES_API_H__ +#define __IP_TYPES_API_H__ + +/** + * Conversion functions to/from (decode/encode) API types to VPP internal types + */ + +#include +#include + +/** + * Forward declarations so we need not #include the API definitions here + */ +struct _vl_api_address; +struct _vl_api_prefix; + +extern void ip_address_decode (const struct _vl_api_address *in, + ip46_address_t * out); +extern void ip_address_encode (const ip46_address_t * in, + struct _vl_api_address *out); + +extern void ip_prefix_decode (const struct _vl_api_prefix *in, + fib_prefix_t * out); +extern void ip_prefix_encode (const fib_prefix_t * in, + struct _vl_api_prefix *out); + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg