/* * Copyright (c) 2016 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 PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_ #define PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_ #include #define SEQ_CHECK_VALUE 0x80000000 /* for seq number wraparound detection */ #define SEQNO_WINDOW_SIZE 2048 #define SEQNO_WINDOW_ARRAY_SIZE 64 typedef struct seqno_bitmap_ { u32 window_size; u32 array_size; u32 mask; u32 pad; u64 highest; u64 array[SEQNO_WINDOW_ARRAY_SIZE]; /* Will be alloc to array_size */ } seqno_bitmap; typedef struct seqno_rx_info_ { u64 rx_packets; u64 lost_packets; u64 reordered_packets; u64 dup_packets; seqno_bitmap bitmap; } seqno_rx_info; /* This structure is 64-byte aligned */ typedef struct ioam_seqno_data_ { union { u32 seq_num; /* Useful only for encap node */ seqno_rx_info seqno_rx; }; } ioam_seqno_data; static inline void BIT_SET (u64 * p, u32 n) { p[n >> 5] |= (1 << (n & 31)); } static inline int BIT_TEST (u64 * p, u32 n) { return p[n >> 5] & (1 << (n & 31)); } static void BIT_CLEAR (u64 * p, u64 start, int num_bits, u32 mask) { int n, t; int start_index = (start >> 5); int mask_index = (mask >> 5); start_index &= mask_index; if (start & 0x1f) { int start_bit = (start & 0x1f); n = (1 << start_bit) - 1; t = start_bit + num_bits; if (t < 32) { n |= ~((1 << t) - 1); p[start_index] &= n; return; } p[start_index] &= n; start_index = (start_index + 1) & mask_index; num_bits -= (32 - start_bit); } while (num_bits >= 32) { p[start_index] = 0; start_index = (start_index + 1) & mask_index; num_bits -= 32; } n = ~((1 << num_bits) - 1); p[start_index] &= n; } static inline u8 seqno_check_wraparound (u32 a, u32 b) { if ((a != b) && (a > b) && ((a - b) > SEQ_CHECK_VALUE)) { return 1; } return 0; } /* * Function to analyze the PPC value recevied. * - Updates the bitmap with received sequence number * - counts the received/lost/duplicate/reordered packets */ inline static void ioam_analyze_seqno (seqno_rx_info * seqno_rx, u64 seqno) { int diff; static int peer_dead_count; seqno_bitmap *bitmap = &seqno_rx->bitmap; seqno_rx->rx_packets++; if (seqno > bitmap->highest) { /* new larger sequence number */ peer_dead_count = 0; diff = seqno - bitmap->highest; if (diff < bitmap->window_size) { if (diff > 1) { /* diff==1 is *such* a common case it's a win to optimize it */ BIT_CLEAR (bitmap->array, bitmap->highest + 1, diff - 1, bitmap->mask); seqno_rx->lost_packets += diff - 1; } } else { seqno_rx->lost_packets += diff - 1; memset (bitmap->array, 0, bitmap->array_size * sizeof (u64)); } BIT_SET (bitmap->array, seqno & bitmap->mask); bitmap->highest = seqno; return; } /* we've seen a bigger seq number before */ diff = bitmap->highest - seqno; if (diff >= bitmap->window_size) { if (seqno_check_wraparound (bitmap->highest, seqno)) { memset (bitmap->array, 0, bitmap->array_size * sizeof (u64)); BIT_SET (bitmap->array, seqno & bitmap->mask); bitmap->highest = seqno; return; } else { peer_dead_count++; if (peer_dead_count > 25) { peer_dead_count = 0; memset (bitmap->array, 0, bitmap->array_size * sizeof (u64)); BIT_SET (bitmap->array, seqno & bitmap->mask); bitmap->highest = seqno; } //ppc_rx->reordered_packets++; } return; } if (BIT_TEST (bitmap->array, seqno & bitmap->mask)) { seqno_rx->dup_packets++; return; /* Already seen */ } seqno_rx->reordered_packets++; seqno_rx->lost_packets--; BIT_SET (bitmap->array, seqno & bitmap->mask); return; } u8 *show_ioam_seqno_analyse_data_fn (u8 * s, seqno_rx_info * rx); u8 *show_ioam_seqno_cmd_fn (u8 * s, ioam_seqno_data * seqno_data, u8 enc); void ioam_seqno_init_data (ioam_seqno_data * data); void ioam_seqno_init_rx_info (seqno_rx_info * data); #endif /* PLUGINS_IOAM_PLUGIN_IOAM_LIB_E2E_IOAM_SEQNO_LIB_H_ */ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */