/* * Copyright (c) 2019 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. * * TCP byte tracker that can generate delivery rate estimates. Based on * draft-cheng-iccrg-delivery-rate-estimation-00 */ #include #include #include static tcp_bt_sample_t * bt_get_sample (tcp_byte_tracker_t * bt, u32 bts_index) { if (pool_is_free_index (bt->samples, bts_index)) return 0; return pool_elt_at_index (bt->samples, bts_index); } static tcp_bt_sample_t * bt_next_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts) { return bt_get_sample (bt, bts->next); } static tcp_bt_sample_t * bt_prev_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts) { return bt_get_sample (bt, bts->prev); } static u32 bt_sample_index (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts) { if (!bts) return TCP_BTS_INVALID_INDEX; return bts - bt->samples; } static inline int bt_seq_lt (u32 a, u32 b) { return seq_lt (a, b); } static tcp_bt_sample_t * bt_alloc_sample (tcp_byte_tracker_t * bt, u32 min_seq, u32 max_seq) { tcp_bt_sample_t *bts; pool_get_zero (bt->samples, bts); bts->next = bts->prev = TCP_BTS_INVALID_INDEX; bts->min_seq = min_seq; bts->max_seq = max_seq; rb_tree_add_custom (&bt->sample_lookup, bts->min_seq, bts - bt->samples, bt_seq_lt); return bts; } static void bt_free_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts) { if (bts->prev != TCP_BTS_INVALID_INDEX) { tcp_bt_sample_t *prev = bt_prev_sample (bt, bts); prev->next = bts->next; } else bt->head = bts->next; if (bts->next != TCP_BTS_INVALID_INDEX) { tcp_bt_sample_t *next = bt_next_sample (bt, bts); next->prev = bts->prev; } else bt->tail = bts->prev; rb_tree_del_custom (&bt->sample_lookup, bts->min_seq, bt_seq_lt); if (CLIB_DEBUG) memset (bts, 0xfc, sizeof (*bts)); pool_put (bt->samples, bts); } static tcp_bt_sample_t * bt_split_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts, u32 seq) { tcp_bt_sample_t *ns, *next; u32 bts_index; bts_index = bt_sample_index (bt, bts); ASSERT (seq_leq (bts->min_seq, seq) && seq_lt (seq, bts->max_seq)); ns = bt_alloc_sample (bt, seq, bts->max_seq); bts = bt_get_sample (bt, bts_index); *ns = *bts; ns->min_seq = seq; bts->max_seq = seq; next = bt_next_sample (bt, bts); if (next) next->prev = bt_sample_index (bt, ns); else bt->tail = bt_sample_index (bt, ns); bts->next = bt_sample_index (bt, ns); ns->prev = bt_sample_index (bt, bts); return ns; } static tcp_bt_sample_t * bt_merge_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * prev, tcp_bt_sample_t * cur) { ASSERT (prev->max_seq == cur->min_seq); prev->max_seq = cur->max_seq; if (bt_sample_index (bt, cur) == bt->tail) bt->tail = bt_sample_index (bt, prev); bt_free_sample (bt, cur); return prev; } static tcp_bt_sample_t * bt_lookup_seq (tcp_byte_tracker_t * bt, u32 seq) { rb_tree_t *rt = &bt->sample_lookup; rb_node_t *cur, *prev; tcp_bt_sample_t *bts; cur = rb_node (rt, rt->root); if (rb_node_is_tnil (rt, cur)) return 0; while (seq != cur->key) { prev = cur; if (seq_lt (seq, cur->key)) cur = rb_node_left (rt, cur); else cur = rb_node_right (rt, cur); if (rb_node_is_tnil (rt, cur)) { /* Hit tnil as a left child. Find predecessor */ if (seq_lt (seq, prev->key)) { cur = rb_tree_predecessor (rt, prev); if (rb_node_is_tnil (rt, cur)) return 0; bts = bt_get_sample (bt, cur->opaque); } /* Hit tnil as a right child */ else { bts = bt_get_sample (bt, prev->opaque); } if (seq_geq (seq, bts->min_seq)) return bts; return 0; } } if (!rb_node_is_tnil (rt, cur)) return bt_get_sample (bt, cur->opaque); return 0; } static void bt_update_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts, u32 seq) { rb_tree_del_custom (&bt->sample_lookup, bts->min_seq, bt_seq_lt); bts->min_seq = seq; rb_tree_add_custom (&bt->sample_lookup, bts->min_seq, bt_sample_index (bt, bts), bt_seq_lt); } static tcp_bt_sample_t * bt_fix_overlapped (tcp_byte_tracker_t * bt, tcp_bt_sample_t * start, u32 seq, u8 is_end) { tcp_bt_sample_t *cur, *next; cur = start; while (cur && seq_leq (cur->max_seq, seq)) { next = bt_next_sample (bt, cur); bt_free_sample (bt, cur); cur = next; } if (cur && seq_lt (cur->min_seq, seq)) bt_update_sample (bt, cur, seq); return cur; } int tcp_bt_is_sane (tcp_byte_tracker_t * bt) { tcp_bt_sample
#!/bin/bash

echo "PCI Address  MAC address       Device Name    Driver     State    Speed      Port Type"
echo "============ ================= ============== ========== ======== ========== ===================="

for f in /sys/class/net/*; do
	dev=$(basename ${f})
	if [ -e $f/device ] ; then
		dev=$(basename ${f})
		pci_addr=$(basename $(readlink $f/device))
		mac=$(cat $f/address)
		driver=$(basename $(readlink $f/device/driver))
		oper=$(cat $f/operstate)
		speed=$(sudo ethtool $dev | grep Speed | cut -d" " -f2)
		port=$(ethtool $dev 2> /dev/null | sed -ne 's/.*Port: \(.*\)/\1/p')
		printf "%-12s %-14s %-14s %-10s %-8s %-10s %-20s\n" $pci_addr $mac $dev $driver $oper $speed "$port"
		# ethtool $dev | grep Port:
	fi
done