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 103 #ifdef PKTDUMP 104 DumpPacket(mtcp, 105 (char *)iph - sizeof(struct ethhdr), 106 pctx->p.ip_len + sizeof(struct ethhdr), 107 "OUT", pctx->out_ifidx); 108 #endif 109 110 } 111 /*----------------------------------------------------------------------------*/ 112 inline void 113 FillOutPacketIPContext(struct pkt_ctx *pctx, struct iphdr *iph, int ip_len) 114 { 115 pctx->p.iph = iph; 116 pctx->p.ip_len = ip_len; 117 118 return; 119 } 120 /*----------------------------------------------------------------------------*/ 121 uint8_t * 122 IPOutputStandalone(struct mtcp_manager *mtcp, 123 uint16_t ip_id, uint32_t saddr, uint32_t daddr, uint16_t tcplen, 124 struct pkt_ctx *pctx, uint32_t cur_ts) 125 { 126 struct iphdr *iph; 127 int nif; 128 unsigned char * haddr; 129 int rc = -1; 130 131 nif = GetOutputInterface(daddr); 132 if (nif < 0) 133 return NULL; 134 135 haddr = GetDestinationHWaddr(daddr); 136 if (!haddr) { 137 #ifdef RUN_ARP 138 /* ARP requests will not be created if it's a standalone middlebox */ 139 /* tcp will retry sending the packet later */ 140 if (!pctx->forward) 141 RequestARP(mtcp, daddr, nif, mtcp->cur_ts); 142 #else 143 uint8_t *da = (uint8_t *)&daddr; 144 TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u " 145 "is not in ARP table!\n", 146 da[0], da[1], da[2], da[3]); 147 #endif 148 return NULL; 149 } 150 151 iph = (struct iphdr *)EthernetOutput(mtcp, pctx, 152 ETH_P_IP, nif, haddr, tcplen + IP_HEADER_LEN, cur_ts); 153 if (!iph) { 154 return NULL; 155 } 156 157 iph->ihl = IP_HEADER_LEN >> 2; 158 iph->version = 4; 159 iph->tos = 0; 160 iph->tot_len = htons(IP_HEADER_LEN + tcplen); 161 iph->id = htons(ip_id); 162 iph->frag_off = htons(0x4000); // no fragmentation 163 iph->ttl = 64; 164 iph->protocol = IPPROTO_TCP; 165 iph->saddr = saddr; 166 iph->daddr = daddr; 167 iph->check = 0; 168 169 /* offload IP checkum if possible */ 170 if (likely(mtcp->iom->dev_ioctl != NULL)) 171 rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph); 172 /* otherwise calculate IP checksum in S/W */ 173 if (rc == -1) 174 iph->check = ip_fast_csum(iph, iph->ihl); 175 176 FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN); 177 178 return (uint8_t *)(iph + 1); 179 } 180 /*----------------------------------------------------------------------------*/ 181 uint8_t * 182 IPOutput(struct mtcp_manager *mtcp, tcp_stream *stream, uint16_t tcplen, 183 struct pkt_ctx *pctx, uint32_t cur_ts) 184 { 185 struct iphdr *iph; 186 int nif; 187 unsigned char *haddr; 188 int rc = -1; 189 190 if (stream->sndvar->nif_out >= 0) { 191 nif = stream->sndvar->nif_out; 192 } else { 193 nif = GetOutputInterface(stream->daddr); 194 stream->sndvar->nif_out = nif; 195 } 196 197 haddr = GetDestinationHWaddr(stream->daddr); 198 if (!haddr) { 199 #ifdef RUN_ARP 200 /* if not found in the arp table, send arp request and return NULL */ 201 /* ARP requests will not be created if it's a standalone middlebox */ 202 /* tcp will retry sending the packet later */ 203 if (!pctx->forward) 204 RequestARP(mtcp, stream->daddr, stream->sndvar->nif_out, mtcp->cur_ts); 205 #else 206 uint8_t *da = (uint8_t *)&stream->daddr; 207 TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u " 208 "is not in ARP table!\n", 209 da[0], da[1], da[2], da[3]); 210 #endif 211 return NULL; 212 } 213 iph = (struct iphdr *)EthernetOutput(mtcp, pctx, ETH_P_IP, 214 stream->sndvar->nif_out, haddr, tcplen + IP_HEADER_LEN, cur_ts); 215 if (!iph) { 216 return NULL; 217 } 218 219 iph->ihl = IP_HEADER_LEN >> 2; 220 iph->version = 4; 221 iph->tos = 0; 222 iph->tot_len = htons(IP_HEADER_LEN + tcplen); 223 iph->id = htons(stream->sndvar->ip_id++); 224 iph->frag_off = htons(0x4000); // no fragmentation 225 iph->ttl = 64; 226 iph->protocol = IPPROTO_TCP; 227 iph->saddr = stream->saddr; 228 iph->daddr = stream->daddr; 229 iph->check = 0; 230 231 /* offload IP checkum if possible */ 232 if (likely(mtcp->iom->dev_ioctl != NULL)) 233 rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph); 234 /* otherwise calculate IP checksum in S/W */ 235 if (rc == -1) 236 iph->check = ip_fast_csum(iph, iph->ihl); 237 238 FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN); 239 240 return (uint8_t *)(iph + 1); 241 } 242