Line data Source code
1 : #ifndef HEADER_fd_src_disco_net_fd_net_router_h 2 : #define HEADER_fd_src_disco_net_fd_net_router_h 3 : 4 : /* fd_net_router.h provides an internal API for userland routing. */ 5 : 6 : #include "fd_net_tile_private.h" 7 : #include "../../waltz/ip/fd_fib4.h" 8 : #include "../../waltz/mib/fd_netdev_tbl.h" 9 : #include "../../waltz/neigh/fd_neigh4_map.h" 10 : #include "../netlink/fd_netlink_tile.h" /* neigh4_solicit */ 11 : #include "../../util/net/fd_eth.h" 12 : #include "../../util/net/fd_ip4.h" 13 : 14 : #include <linux/if_arp.h> /* ARPHRD_LOOPBACK */ 15 : 16 : struct fd_net_router { 17 : ulong netlnk_out_idx; 18 : uint solicit_ip; 19 : uint solicit_if_idx; 20 : 21 : /* Route and neighbor tables */ 22 : fd_fib4_t fib_local[1]; 23 : fd_fib4_t fib_main[1]; 24 : fd_neigh4_hmap_t neigh4[1]; 25 : 26 : /* Netdev table */ 27 : fd_netdev_tbl_join_t netdev_tbl; /* local copy in scratch */ 28 : fd_netdev_tbl_join_t netdev_shared; /* shared seqlock-protected table */ 29 : 30 : uint if_virt; 31 : uint bind_address; 32 : uint default_address; 33 : 34 : struct { 35 : ulong tx_neigh_fail_cnt; 36 : } metrics; 37 : }; 38 : typedef struct fd_net_router fd_net_router_t; 39 : 40 : FD_PROTOTYPES_BEGIN 41 : 42 : /* fd_net_tx_route resolves the destination interface index, src MAC 43 : address, and dst MAC address. Returns 1 on success, 0 on failure. 44 : On success, writes the complete route result to out. */ 45 : 46 : static int 47 : fd_net_tx_route( fd_net_router_t * ctx, 48 : fd_net_tile_t * net, 49 : uint dst_ip, 50 0 : fd_net_tx_route_t * out ) { 51 : 52 0 : if( FD_UNLIKELY( !out ) ) return 0; 53 0 : *out = (fd_net_tx_route_t) {0}; 54 : 55 : /* Route lookup */ 56 : 57 0 : fd_fib4_hop_t hop[2] = {0}; 58 0 : hop[0] = fd_fib4_lookup( ctx->fib_local, dst_ip, 0UL ); 59 0 : hop[1] = fd_fib4_lookup( ctx->fib_main, dst_ip, 0UL ); 60 0 : fd_fib4_hop_t const * next_hop = fd_fib4_hop_or( hop+0, hop+1 ); 61 : 62 0 : uint rtype = next_hop->rtype; 63 0 : uint if_idx = next_hop->if_idx; 64 0 : uint ip4_src = next_hop->ip4_src; 65 : 66 0 : if( FD_UNLIKELY( rtype==FD_FIB4_RTYPE_LOCAL ) ) { 67 0 : rtype = FD_FIB4_RTYPE_UNICAST; 68 0 : if_idx = 1; 69 0 : } 70 : 71 0 : if( FD_UNLIKELY( rtype!=FD_FIB4_RTYPE_UNICAST ) ) { 72 0 : uint const reason = fd_uint_if( rtype==FD_FIB4_RTYPE_THROW, 73 0 : FD_METRICS_ENUM_PKT_TX_DROP_REASON_V_NO_ROUTE_IDX, 74 0 : FD_METRICS_ENUM_PKT_TX_DROP_REASON_V_UNSUPPORTED_ROUTE_IDX ); 75 0 : net->metrics.tx_drop_cnt[ reason ]++; 76 0 : return 0; 77 0 : } 78 : 79 0 : fd_netdev_t * netdev = fd_netdev_tbl_query( &ctx->netdev_tbl, if_idx ); 80 0 : if( !netdev ) { 81 0 : net->metrics.tx_drop_cnt[ FD_METRICS_ENUM_PKT_TX_DROP_REASON_V_INTERFACE_MISSING_IDX ]++; 82 0 : return 0; 83 0 : } 84 : 85 0 : ip4_src = fd_uint_if( !!ctx->bind_address, ctx->bind_address, ip4_src ); 86 0 : out->mtu = netdev->mtu; 87 0 : out->src_ip = ip4_src; 88 0 : out->if_idx = if_idx; 89 : 90 0 : if( netdev->dev_type==ARPHRD_LOOPBACK ) { 91 0 : memset( out->mac_addrs, 0, sizeof(out->mac_addrs) ); 92 0 : out->src_ip = fd_uint_if( !ip4_src, FD_IP4_ADDR( 127,0,0,1 ), ip4_src ); 93 0 : out->use_loopback = 1U; 94 0 : return 1; 95 0 : } else if( netdev->dev_type==ARPHRD_IPGRE ) { 96 : /* skip MAC addrs lookup for GRE inner dst ip */ 97 0 : out->gre_outer_src_ip = netdev->gre_src_ip; 98 0 : out->gre_outer_dst_ip = netdev->gre_dst_ip; 99 0 : out->use_gre = 1U; 100 0 : return 1; 101 0 : } 102 : 103 0 : if( FD_UNLIKELY( netdev->dev_type!=ARPHRD_ETHER ) ) { 104 0 : net->metrics.tx_drop_cnt[ FD_METRICS_ENUM_PKT_TX_DROP_REASON_V_UNSUPPORTED_INTERFACE_IDX ]++; 105 0 : return 0; 106 0 : } 107 : 108 0 : if( FD_UNLIKELY( if_idx!=ctx->if_virt ) ) { 109 0 : net->metrics.tx_drop_cnt[ FD_METRICS_ENUM_PKT_TX_DROP_REASON_V_UNSUPPORTED_INTERFACE_IDX ]++; 110 0 : return 0; 111 0 : } 112 : 113 : /* Neighbor resolve */ 114 0 : uint neigh_ip = next_hop->ip4_gw; 115 0 : if( !neigh_ip ) neigh_ip = dst_ip; 116 : 117 0 : fd_neigh4_entry_t neigh[1]; 118 0 : int neigh_res = fd_neigh4_hmap_query_entry( ctx->neigh4, neigh_ip, neigh ); 119 0 : if( FD_UNLIKELY( neigh_res!=FD_MAP_SUCCESS ) ) { 120 : /* Neighbor not found */ 121 0 : ctx->solicit_ip = neigh_ip; 122 0 : ctx->solicit_if_idx = if_idx; 123 0 : ctx->metrics.tx_neigh_fail_cnt++; 124 0 : return 0; 125 0 : } 126 0 : if( FD_UNLIKELY( neigh->state != FD_NEIGH4_STATE_ACTIVE ) ) { 127 0 : ctx->metrics.tx_neigh_fail_cnt++; 128 0 : return 0; 129 0 : } 130 0 : ip4_src = fd_uint_if( !ip4_src, ctx->default_address, ip4_src ); 131 0 : out->src_ip = ip4_src; 132 0 : memcpy( out->mac_addrs+0, neigh->mac_addr, 6 ); 133 0 : memcpy( out->mac_addrs+6, netdev->mac_addr, 6 ); 134 : 135 0 : return 1; 136 0 : } 137 : 138 : static inline void 139 : fd_net_router_solicit( fd_net_router_t * ctx, 140 0 : fd_stem_context_t * stem ) { 141 0 : if( FD_LIKELY( !ctx->solicit_ip ) ) return; 142 : 143 0 : fd_stem_publish( stem, ctx->netlnk_out_idx, fd_netlink_neigh4_solicit_sig( ctx->solicit_ip, ctx->solicit_if_idx ), 0UL, 0UL, 0UL, 0UL, fd_frag_meta_ts_comp( fd_tickcount() ) ); 144 0 : ctx->solicit_ip = 0U; 145 0 : } 146 : 147 : FD_PROTOTYPES_END 148 : 149 : #endif /* HEADER_fd_src_disco_net_fd_net_router_h */