1 #include <string.h> 2 3 #include "ip_out.h" 4 #include "ip_in.h" 5 #include "eth_out.h" 6 #include "arp.h" 7 #include "debug.h" 8 #include "config.h" 9 10 /*----------------------------------------------------------------------------*/ 11 inline int 12 GetOutputInterface(uint32_t daddr) 13 { 14 int nif = -1; 15 int i; 16 int prefix = -1; 17 18 /* Longest prefix matching */ 19 for (i = 0; i < g_config.mos->route_table->num; i++) { 20 if ((daddr & g_config.mos->route_table->ent[i]->mask) 21 == g_config.mos->route_table->ent[i]->masked_ip) { 22 if (g_config.mos->route_table->ent[i]->prefix > prefix) { 23 nif = g_config.mos->route_table->ent[i]->nif; 24 prefix = g_config.mos->route_table->ent[i]->prefix; 25 } 26 } 27 } 28 29 if (nif < 0) { 30 uint8_t *da = (uint8_t *)&daddr; 31 TRACE_ERROR("[WARNING] No route to %u.%u.%u.%u\n", 32 da[0], da[1], da[2], da[3]); 33 assert(0); 34 } 35 36 return nif; 37 } 38 /*----------------------------------------------------------------------------*/ 39 void 40 ForwardIPPacket(mtcp_manager_t mtcp, struct pkt_ctx *pctx) 41 { 42 unsigned char * haddr; 43 struct iphdr *iph; 44 uint32_t daddr = 0; 45 46 if (g_config.mos->nic_forward_table != NULL) { 47 pctx->out_ifidx = 48 g_config.mos->nic_forward_table->nic_fwd_table[pctx->p.in_ifidx]; 49 if (pctx->out_ifidx != -1) { 50 haddr = pctx->p.ethh->h_dest; 51 goto fast_tx; 52 } 53 } 54 55 /* set daddr for easy code writing */ 56 daddr = pctx->p.iph->daddr; 57 58 if (pctx->out_ifidx < 0) { 59 pctx->out_ifidx = GetOutputInterface(pctx->p.iph->daddr); 60 if (pctx->out_ifidx < 0) { 61 return; 62 } 63 } 64 65 haddr = GetDestinationHWaddr(daddr); 66 if (!haddr) { 67 #ifdef RUN_ARP 68 /* ARP requests will not be created if it's a standalone middlebox */ 69 if (!pctx->forward) 70 RequestARP(mtcp, daddr, 71 pctx->out_ifidx, pctx->p.cur_ts); 72 #else 73 uint8_t *da = (uint8_t *)&(pctx->p.iph->daddr); 74 TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u " 75 "is not in ARP table!\n", 76 da[0], da[1], da[2], da[3]); 77 #endif 78 return; 79 } 80 81 #ifdef SHARE_IO_BUFFER 82 if (likely(mtcp->iom->set_wptr != NULL)) { 83 int i; 84 for (i = 0; i < ETH_ALEN; i++) { 85 pctx->p.ethh->h_source[i] = g_config.mos->netdev_table->ent[pctx->out_ifidx]->haddr[i]; 86 pctx->p.ethh->h_dest[i] = haddr[i]; 87 } 88 mtcp->iom->set_wptr(mtcp->ctx, pctx->out_ifidx, pctx->p.in_ifidx, pctx->batch_index); 89 return; 90 } 91 #endif 92 93 fast_tx: 94 iph = (struct iphdr *) EthernetOutput (mtcp, pctx, ETH_P_IP, 95 pctx->out_ifidx, haddr, pctx->p.ip_len, pctx->p.cur_ts); 96 if (iph) 97 memcpy(iph, pctx->p.iph, pctx->p.ip_len); 98 else 99 TRACE_ERROR("Failed to send a packet\n" 100 "NULL = EthernetOutput(%p, %d, %d, %p, %d)\n", 101 mtcp, ETH_P_IP, pctx->out_ifidx, haddr, pctx->p.ip_len); 102 #ifdef PKTDUMP 103 DumpPacket(mtcp, 104 (char *)iph - sizeof(struct ethhdr), 105 pctx->p.ip_len + sizeof(struct ethhdr), 106 "OUT", pctx->out_ifidx); 107 #endif 108 } 109 /*----------------------------------------------------------------------------*/ 110 inline void 111 FillOutPacketIPContext(struct pkt_ctx *pctx, struct iphdr *iph, int ip_len) 112 { 113 pctx->p.iph = iph; 114 pctx->p.ip_len = ip_len; 115 116 return; 117 } 118 /*----------------------------------------------------------------------------*/ 119 uint8_t * 120 IPOutputStandalone(struct mtcp_manager *mtcp, 121 uint16_t ip_id, uint32_t saddr, uint32_t daddr, uint16_t tcplen, 122 struct pkt_ctx *pctx, uint32_t cur_ts) 123 { 124 struct iphdr *iph; 125 int nif; 126 unsigned char * haddr; 127 int rc = -1; 128 129 nif = GetOutputInterface(daddr); 130 if (nif < 0) 131 return NULL; 132 133 haddr = GetDestinationHWaddr(daddr); 134 if (!haddr) { 135 #ifdef RUN_ARP 136 /* ARP requests will not be created if it's a standalone middlebox */ 137 /* tcp will retry sending the packet later */ 138 if (!pctx->forward) 139 RequestARP(mtcp, daddr, nif, mtcp->cur_ts); 140 #else 141 uint8_t *da = (uint8_t *)&daddr; 142 TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u " 143 "is not in ARP table!\n", 144 da[0], da[1], da[2], da[3]); 145 #endif 146 return NULL; 147 } 148 149 iph = (struct iphdr *)EthernetOutput(mtcp, pctx, 150 ETH_P_IP, nif, haddr, tcplen + IP_HEADER_LEN, cur_ts); 151 if (!iph) { 152 return NULL; 153 } 154 155 iph->ihl = IP_HEADER_LEN >> 2; 156 iph->version = 4; 157 iph->tos = 0; 158 iph->tot_len = htons(IP_HEADER_LEN + tcplen); 159 iph->id = htons(ip_id); 160 iph->frag_off = htons(0x4000); // no fragmentation 161 iph->ttl = 64; 162 iph->protocol = IPPROTO_TCP; 163 iph->saddr = saddr; 164 iph->daddr = daddr; 165 iph->check = 0; 166 167 /* offload IP checkum if possible */ 168 if (likely(mtcp->iom->dev_ioctl != NULL)) 169 rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph); 170 /* otherwise calculate IP checksum in S/W */ 171 if (rc == -1) 172 iph->check = ip_fast_csum(iph, iph->ihl); 173 174 FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN); 175 176 return (uint8_t *)(iph + 1); 177 } 178 /*----------------------------------------------------------------------------*/ 179 uint8_t * 180 IPOutput(struct mtcp_manager *mtcp, tcp_stream *stream, uint16_t tcplen, 181 struct pkt_ctx *pctx, uint32_t cur_ts) 182 { 183 struct iphdr *iph; 184 int nif; 185 unsigned char *haddr; 186 int rc = -1; 187 188 if (stream->sndvar->nif_out >= 0) { 189 nif = stream->sndvar->nif_out; 190 } else { 191 nif = GetOutputInterface(stream->daddr); 192 stream->sndvar->nif_out = nif; 193 } 194 195 haddr = GetDestinationHWaddr(stream->daddr); 196 if (!haddr) { 197 #ifdef RUN_ARP 198 /* if not found in the arp table, send arp request and return NULL */ 199 /* ARP requests will not be created if it's a standalone middlebox */ 200 /* tcp will retry sending the packet later */ 201 if (!pctx->forward) 202 RequestARP(mtcp, stream->daddr, stream->sndvar->nif_out, mtcp->cur_ts); 203 #else 204 uint8_t *da = (uint8_t *)&stream->daddr; 205 TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u " 206 "is not in ARP table!\n", 207 da[0], da[1], da[2], da[3]); 208 #endif 209 return NULL; 210 } 211 iph = (struct iphdr *)EthernetOutput(mtcp, pctx, ETH_P_IP, 212 stream->sndvar->nif_out, haddr, tcplen + IP_HEADER_LEN, cur_ts); 213 if (!iph) { 214 return NULL; 215 } 216 217 iph->ihl = IP_HEADER_LEN >> 2; 218 iph->version = 4; 219 iph->tos = 0; 220 iph->tot_len = htons(IP_HEADER_LEN + tcplen); 221 iph->id = htons(stream->sndvar->ip_id++); 222 iph->frag_off = htons(0x4000); // no fragmentation 223 iph->ttl = 64; 224 iph->protocol = IPPROTO_TCP; 225 iph->saddr = stream->saddr; 226 iph->daddr = stream->daddr; 227 iph->check = 0; 228 229 /* offload IP checkum if possible */ 230 if (likely(mtcp->iom->dev_ioctl != NULL)) 231 rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph); 232 /* otherwise calculate IP checksum in S/W */ 233 if (rc == -1) 234 iph->check = ip_fast_csum(iph, iph->ihl); 235 236 FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN); 237 238 return (uint8_t *)(iph + 1); 239 } 240