Line data Source code
1 : #include "fd_neigh4_netlink.h" 2 : 3 : #include <errno.h> 4 : #include <sys/socket.h> /* AF_INET */ 5 : #include <linux/netlink.h> /* struct nlmsghdr */ 6 : #include <linux/rtnetlink.h> /* RTM_NEWNEIGH */ 7 : #include <linux/neighbour.h> /* struct ndmsg */ 8 : #include "../ip/fd_netlink1.h" 9 : #include "fd_neigh4_map.h" 10 : 11 : int 12 : fd_neigh4_netlink_request_dump( fd_netlink_t * netlink, 13 0 : uint if_idx ) { 14 : 15 0 : uint seq = netlink->seq++; 16 : 17 0 : struct { 18 0 : struct nlmsghdr nlh; 19 0 : struct ndmsg ndm; 20 0 : } request; 21 0 : request.nlh = (struct nlmsghdr) { 22 0 : .nlmsg_type = RTM_GETNEIGH, 23 0 : .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, 24 0 : .nlmsg_len = sizeof(request), 25 0 : .nlmsg_seq = seq 26 0 : }; 27 0 : request.ndm = (struct ndmsg) { 28 0 : .ndm_family = AF_INET, 29 0 : .ndm_ifindex = (int)if_idx 30 0 : }; 31 : 32 0 : long send_res = send( netlink->fd, &request, sizeof(request), 0 ); 33 0 : if( FD_UNLIKELY( send_res<0 ) ) { 34 0 : FD_LOG_WARNING(( "netlink send(RTM_GETNEIGH,NLM_F_REQUEST|NLM_F_DUMP) failed (%d-%s)", errno, fd_io_strerror( errno ) )); 35 0 : return errno; 36 0 : } 37 0 : if( FD_UNLIKELY( send_res!=sizeof(request ) ) ) { 38 0 : FD_LOG_WARNING(( "netlink send(RTM_GETNEIGH,NLM_F_REQUEST|NLM_F_DUMP) failed (short write)" )); 39 0 : return EPIPE; 40 0 : } 41 : 42 0 : return 0; 43 0 : } 44 : 45 : void 46 : fd_neigh4_netlink_ingest_message( fd_neigh4_hmap_t * map, 47 : struct nlmsghdr const * msg_hdr, 48 0 : uint if_idx ) { 49 0 : if( FD_UNLIKELY( msg_hdr->nlmsg_type!=RTM_NEWNEIGH && msg_hdr->nlmsg_type!=RTM_DELNEIGH ) ) { 50 0 : FD_LOG_WARNING(( "unexpected nlmsg_type %u", msg_hdr->nlmsg_type )); 51 0 : return; 52 0 : } 53 : 54 0 : struct ndmsg const * ndm = NLMSG_DATA( msg_hdr ); 55 0 : struct rtattr const * rat = RTM_RTA( ndm ); 56 0 : long rat_sz = (long)(int)RTM_PAYLOAD( msg_hdr ); 57 : 58 0 : if( FD_UNLIKELY( ndm->ndm_family!=AF_INET ) ) return; 59 0 : if( FD_UNLIKELY( (uint)ndm->ndm_ifindex!=if_idx ) ) return; 60 : 61 0 : uint ip4_dst = 0U; 62 0 : union { 63 0 : uchar u6[6]; 64 0 : ulong ul; 65 0 : } mac_addr = {0}; 66 : 67 0 : for( ; RTA_OK( rat, rat_sz ); rat=RTA_NEXT( rat, rat_sz ) ) { 68 : 69 0 : void * rta = RTA_DATA( rat ); 70 0 : ulong rta_sz = RTA_PAYLOAD( rat ); 71 : 72 0 : switch( rat->rta_type ) { 73 : 74 0 : case NDA_DST: 75 0 : if( FD_UNLIKELY( rta_sz!=4UL ) ) { 76 0 : FD_LOG_WARNING(( "unexpected NDA_DST size %lu", rta_sz )); 77 0 : return; 78 0 : } 79 0 : ip4_dst = FD_LOAD( uint, rta ); /* big endian */ 80 0 : break; 81 : 82 0 : case NDA_LLADDR: 83 0 : if( FD_UNLIKELY( rta_sz!=6UL ) ) { 84 0 : FD_LOG_WARNING(( "unexpected NDA_LLADDR size %lu (is this an Ethernet interface?)", rta_sz )); 85 0 : return; 86 0 : } 87 0 : memcpy( mac_addr.u6, rta, 6 ); 88 0 : break; 89 : 90 0 : default: 91 0 : break; /* ignore */ 92 0 : } 93 : 94 0 : } 95 : 96 0 : if( FD_UNLIKELY( !mac_addr.ul || !ip4_dst ) ) { 97 0 : FD_LOG_DEBUG(( "Ignoring neighbor table update with missing or invalid L2 or L3 address" )); 98 0 : return; 99 0 : } 100 : 101 : /* Determine if we should remove or insert/update entry */ 102 : 103 0 : int remove = 0; 104 0 : switch( ndm->ndm_state ) { 105 0 : case NUD_REACHABLE: 106 0 : case NUD_STALE: 107 0 : case NUD_DELAY: 108 0 : case NUD_PROBE: 109 0 : case NUD_PERMANENT: 110 0 : remove = 0; 111 0 : break; 112 0 : default: 113 0 : remove = 1; 114 0 : break; 115 0 : } 116 0 : if( msg_hdr->nlmsg_type==RTM_DELNEIGH ) { 117 0 : remove = 1; 118 0 : } 119 : 120 : /* Perform update */ 121 : 122 0 : if( remove ) { 123 : 124 0 : fd_neigh4_hmap_remove( map, &ip4_dst, NULL, FD_MAP_FLAG_BLOCKING ); 125 : 126 0 : } else { 127 : 128 0 : fd_neigh4_hmap_query_t query[1]; 129 0 : int prepare_res = fd_neigh4_hmap_prepare( map, &ip4_dst, NULL, query, FD_MAP_FLAG_BLOCKING ); 130 0 : if( FD_UNLIKELY( prepare_res!=FD_MAP_SUCCESS ) ) { 131 0 : FD_LOG_WARNING(( "Failed to update neighbor table" )); 132 0 : return; 133 0 : } 134 : 135 0 : fd_neigh4_entry_t * ele = fd_neigh4_hmap_query_ele( query ); 136 : 137 0 : ele->state = FD_NEIGH4_STATE_ACTIVE; 138 0 : ele->ip4_addr = ip4_dst; 139 0 : memcpy( ele->mac_addr, mac_addr.u6, 6 ); 140 : 141 0 : fd_neigh4_hmap_publish( query ); 142 : 143 0 : } 144 : 145 0 : }