Change PerfMap API so that individual buffers can be read from multiple
threads.
Change the way maps are stored in the `Bpf` struct from RefCell to a
custom RwLock.
Use BpfError::RelocationError for both maps and BTF relocations. The
error includes the name of the program that failed, and the source error
stored as Box<dyn Error>.
This hides the implementation details of the source errors - which are
unrecoverable anyway - while still allowing fine grained error messages.
program() and program_mut() are now generic and can return the inner
program type, which is what you want 99.999% of the time, eg:
let prog = bpf.program_mut::<&mut Xdp>("foo")?.unwrap();
prog.load()?;
prog.attach("eth0")?;
The methods will fail if the requested program is not of the expected
type (eg if you try to retrieve a kprobe as an xdp program).
map() and map_mut() used to return Ref<Map>, then to convert to a concrete
type you had to:
let mut perf_map: PerfMap<_> = bpf.map_mut("PERF_MAP").unwrap().try_into()?;;
But the base Map type is pretty much only useful internally. This change
makes map() and map_mut() use TryInto internally, so that now
conversions can can be done with:
let mut perf_map: PerfMap<_> = bpf.map_mut("PERF_MAP")?.unwrap();