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