123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206openCtypesopenForeign(* --- to be upstreamed to ctypes --- *)letcastptypp=from_voidptyp(to_voidpp)letread_nullabletp=ifp=nullthenNoneelseSome!@(castpt(allocate(ptrvoid)p))letwrite_nullablet=function|None->null|Somef->!@(castp(ptrvoid)(allocatetf))letnullable_viewt=letread=read_nullabletandwrite=write_nullabletinview~read~write(ptrvoid)letstring_opt=nullable_viewstring(* --- *)(* The library names vary by distribution, so use a search list *)letlibnl_names=["libnl-3.so";"libnl-3.so.200";(* Debian/Ubuntu *)]letlibnl_route_names=["libnl-route-3.so";"libnl-route-3.so.200";(* Debian/Ubuntu *)]letdlopen~filenames~flags=letrecloop=function|[]->failwith(Printf.sprintf"Failed to open any of these libraries: [ %s ] (is the package missing?)"(String.concat", "filenames))|n::ns->tryDl.dlopen~filename:n~flagswith_->loopnsinloopfilenamesletlibnl=dlopen~filenames:libnl_names~flags:[Dl.RTLD_LAZY]letlibnl_route=dlopen~filenames:libnl_route_names~flags:[Dl.RTLD_LAZY]moduleSocket=structtypetlett:tstructuretyp=structure"nl_sock"typeprotocol=NETLINK_ROUTEletint_of_protocol=function|NETLINK_ROUTE->0letprotocol_of_int=function|0->NETLINK_ROUTE|_->invalid_arg"protocol"letprotocol=view~read:protocol_of_int~write:int_of_protocolintletalloc=foreign~from:libnl"nl_socket_alloc"(void@->returning(ptrt))letfree=foreign~from:libnl"nl_socket_free"(ptrt@->returningvoid)exceptionConnect_failedletconnect'=foreign~from:libnl"nl_connect"(ptrt@->protocol@->returningint)letconnectsp=letret=connect'spinifret=0then()elseraiseConnect_failedletclose=foreign~from:libnl"nl_close"(ptrt@->returningvoid)endmoduleCache=structlett=ptrvoidletfree'=foreign~from:libnl"nl_cache_free"(t@->returningvoid)letfreecache=free'(!@cache)letiterfcachety=letcallback_t=ptrty@->ptrvoid@->returningvoidinletforeach=foreign~from:libnl"nl_cache_foreach"(t@->funptrcallback_t@->ptrvoid@->returningvoid)inletf'x_=fxinforeach(!@cache)f'nullletto_listcachety=letget_first=foreign~from:libnl"nl_cache_get_first"(t@->returning(ptrty))inletget_prev=foreign~from:libnl"nl_cache_get_prev"(ptrty@->returning(ptrty))inletget_last=foreign~from:libnl"nl_cache_get_last"(t@->returning(ptrty))inletfirst=get_first(!@cache)inletrecloopobjac=ifobj=firstthenobj::acelseloop(get_prevobj)(obj::ac)inloop(get_last(!@cache))[]endtypeaddrletaddr:addrstructuretyp=structure"nl_addr"letaddr_to_string'=foreign~from:libnl"nl_addr2str"(ptraddr@->string@->returningstring)letaddr_to_stringaddr=letbuf=String.make128' 'inaddr_to_string'addrbufmoduleLink=structtypettypestat_id=RX_PACKETS|TX_PACKETS|RX_BYTES|TX_BYTES|RX_ERRORS|TX_ERRORSletint_of_stat_id=function|RX_PACKETS->0|TX_PACKETS->1|RX_BYTES->2|TX_BYTES->3|RX_ERRORS->4|TX_ERRORS->5letstat_id_of_int=function|0->RX_PACKETS|1->TX_PACKETS|2->RX_BYTES|3->TX_BYTES|4->RX_ERRORS|5->TX_ERRORS|_->invalid_arg"stat_id"letstat_id=view~read:stat_id_of_int~write:int_of_stat_idintlett:tstructuretyp=structure"rtnl_link"letalloc_cache'=foreign~from:libnl_route"rtnl_link_alloc_cache"(ptrSocket.t@->int@->ptrCache.t@->returningint)letcache_allocs=letcache=allocateCache.tnullinlet_=alloc_cache's0cacheincacheletcache_iterfcache=Cache.iterfcachetletcache_to_listcache=Cache.to_listcachetletget_by_name=foreign~from:libnl_route"rtnl_link_get_by_name"(Cache.t@->string@->returning(ptrt))letput=foreign~from:libnl_route"rtnl_link_put"(ptrt@->returningvoid)letget_ifindex=foreign~from:libnl_route"rtnl_link_get_ifindex"(ptrt@->returningint)letget_name=foreign~from:libnl_route"rtnl_link_get_name"(ptrt@->returningstring)letget_mtu=foreign~from:libnl_route"rtnl_link_get_mtu"(ptrt@->returningint)letget_stat=foreign~from:libnl_route"rtnl_link_get_stat"(ptrt@->stat_id@->returninguint64_t)letget_addr=foreign~from:libnl_route"rtnl_link_get_addr"(ptrt@->returning(ptraddr))endmoduleAddress=structtypetlett:tstructuretyp=structure"rtnl_addr"letalloc_cache'=foreign~from:libnl_route"rtnl_addr_alloc_cache"(ptrSocket.t@->ptrCache.t@->returningint)letcache_allocs=letcache=allocateCache.tnullinlet_=alloc_cache'scacheincacheletcache_iterfcache=Cache.iterfcachetletcache_to_listcache=Cache.to_listcachetletget_ifindex=foreign~from:libnl_route"rtnl_addr_get_ifindex"(ptrt@->returningint)letget_label=foreign~from:libnl_route"rtnl_addr_get_label"(ptrt@->returningstring_opt)letget_local=foreign~from:libnl_route"rtnl_addr_get_local"(ptrt@->returning(ptraddr))end