176404edcSAsim Jamshed #include <string.h>
276404edcSAsim Jamshed
376404edcSAsim Jamshed #include "ip_out.h"
476404edcSAsim Jamshed #include "ip_in.h"
576404edcSAsim Jamshed #include "eth_out.h"
676404edcSAsim Jamshed #include "arp.h"
776404edcSAsim Jamshed #include "debug.h"
876404edcSAsim Jamshed #include "config.h"
976404edcSAsim Jamshed
1076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
1176404edcSAsim Jamshed inline int
GetOutputInterface(uint32_t daddr)1276404edcSAsim Jamshed GetOutputInterface(uint32_t daddr)
1376404edcSAsim Jamshed {
1476404edcSAsim Jamshed int nif = -1;
1576404edcSAsim Jamshed int i;
1676404edcSAsim Jamshed int prefix = -1;
1776404edcSAsim Jamshed
1876404edcSAsim Jamshed /* Longest prefix matching */
1976404edcSAsim Jamshed for (i = 0; i < g_config.mos->route_table->num; i++) {
2076404edcSAsim Jamshed if ((daddr & g_config.mos->route_table->ent[i]->mask)
2176404edcSAsim Jamshed == g_config.mos->route_table->ent[i]->masked_ip) {
2276404edcSAsim Jamshed if (g_config.mos->route_table->ent[i]->prefix > prefix) {
2376404edcSAsim Jamshed nif = g_config.mos->route_table->ent[i]->nif;
2476404edcSAsim Jamshed prefix = g_config.mos->route_table->ent[i]->prefix;
2576404edcSAsim Jamshed }
2676404edcSAsim Jamshed }
2776404edcSAsim Jamshed }
2876404edcSAsim Jamshed
2976404edcSAsim Jamshed if (nif < 0) {
3076404edcSAsim Jamshed uint8_t *da = (uint8_t *)&daddr;
3176404edcSAsim Jamshed TRACE_ERROR("[WARNING] No route to %u.%u.%u.%u\n",
3276404edcSAsim Jamshed da[0], da[1], da[2], da[3]);
3376404edcSAsim Jamshed assert(0);
3476404edcSAsim Jamshed }
3576404edcSAsim Jamshed
3676404edcSAsim Jamshed return nif;
3776404edcSAsim Jamshed }
3876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
3976404edcSAsim Jamshed void
ForwardIPPacket(mtcp_manager_t mtcp,struct pkt_ctx * pctx)4076404edcSAsim Jamshed ForwardIPPacket(mtcp_manager_t mtcp, struct pkt_ctx *pctx)
4176404edcSAsim Jamshed {
4276404edcSAsim Jamshed unsigned char * haddr;
4376404edcSAsim Jamshed struct iphdr *iph;
4476404edcSAsim Jamshed uint32_t daddr = 0;
4576404edcSAsim Jamshed
4676404edcSAsim Jamshed if (g_config.mos->nic_forward_table != NULL) {
4776404edcSAsim Jamshed pctx->out_ifidx =
48a834ea89SAsim Jamshed g_config.mos->nic_forward_table->nic_fwd_table[pctx->p.in_ifidx];
4976404edcSAsim Jamshed if (pctx->out_ifidx != -1) {
5076404edcSAsim Jamshed haddr = pctx->p.ethh->h_dest;
5176404edcSAsim Jamshed goto fast_tx;
5276404edcSAsim Jamshed }
5376404edcSAsim Jamshed }
5476404edcSAsim Jamshed
5576404edcSAsim Jamshed /* set daddr for easy code writing */
5676404edcSAsim Jamshed daddr = pctx->p.iph->daddr;
5776404edcSAsim Jamshed
5876404edcSAsim Jamshed if (pctx->out_ifidx < 0) {
5976404edcSAsim Jamshed pctx->out_ifidx = GetOutputInterface(pctx->p.iph->daddr);
6076404edcSAsim Jamshed if (pctx->out_ifidx < 0) {
6176404edcSAsim Jamshed return;
6276404edcSAsim Jamshed }
6376404edcSAsim Jamshed }
6476404edcSAsim Jamshed
6576404edcSAsim Jamshed haddr = GetDestinationHWaddr(daddr);
6676404edcSAsim Jamshed if (!haddr) {
6776404edcSAsim Jamshed #ifdef RUN_ARP
6876404edcSAsim Jamshed /* ARP requests will not be created if it's a standalone middlebox */
6976404edcSAsim Jamshed if (!pctx->forward)
7076404edcSAsim Jamshed RequestARP(mtcp, daddr,
7176404edcSAsim Jamshed pctx->out_ifidx, pctx->p.cur_ts);
7276404edcSAsim Jamshed #else
7376404edcSAsim Jamshed uint8_t *da = (uint8_t *)&(pctx->p.iph->daddr);
7476404edcSAsim Jamshed TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
7576404edcSAsim Jamshed "is not in ARP table!\n",
7676404edcSAsim Jamshed da[0], da[1], da[2], da[3]);
7776404edcSAsim Jamshed #endif
7876404edcSAsim Jamshed return;
7976404edcSAsim Jamshed }
8076404edcSAsim Jamshed
8176404edcSAsim Jamshed #ifdef SHARE_IO_BUFFER
8276404edcSAsim Jamshed if (likely(mtcp->iom->set_wptr != NULL)) {
8376404edcSAsim Jamshed int i;
8476404edcSAsim Jamshed for (i = 0; i < ETH_ALEN; i++) {
8576404edcSAsim Jamshed pctx->p.ethh->h_source[i] = g_config.mos->netdev_table->ent[pctx->out_ifidx]->haddr[i];
8676404edcSAsim Jamshed pctx->p.ethh->h_dest[i] = haddr[i];
8776404edcSAsim Jamshed }
88a834ea89SAsim Jamshed mtcp->iom->set_wptr(mtcp->ctx, pctx->out_ifidx, pctx->p.in_ifidx, pctx->batch_index);
8976404edcSAsim Jamshed return;
9076404edcSAsim Jamshed }
9176404edcSAsim Jamshed #endif
9276404edcSAsim Jamshed
9376404edcSAsim Jamshed fast_tx:
9476404edcSAsim Jamshed iph = (struct iphdr *) EthernetOutput (mtcp, pctx, ETH_P_IP,
9576404edcSAsim Jamshed pctx->out_ifidx, haddr, pctx->p.ip_len, pctx->p.cur_ts);
9676404edcSAsim Jamshed if (iph)
9776404edcSAsim Jamshed memcpy(iph, pctx->p.iph, pctx->p.ip_len);
9876404edcSAsim Jamshed else
9976404edcSAsim Jamshed TRACE_ERROR("Failed to send a packet\n"
10076404edcSAsim Jamshed "NULL = EthernetOutput(%p, %d, %d, %p, %d)\n",
10176404edcSAsim Jamshed mtcp, ETH_P_IP, pctx->out_ifidx, haddr, pctx->p.ip_len);
102*05e3289cSYoungGyoun
10376404edcSAsim Jamshed #ifdef PKTDUMP
10476404edcSAsim Jamshed DumpPacket(mtcp,
10576404edcSAsim Jamshed (char *)iph - sizeof(struct ethhdr),
10676404edcSAsim Jamshed pctx->p.ip_len + sizeof(struct ethhdr),
10776404edcSAsim Jamshed "OUT", pctx->out_ifidx);
10876404edcSAsim Jamshed #endif
109*05e3289cSYoungGyoun
11076404edcSAsim Jamshed }
11176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
11276404edcSAsim Jamshed inline void
FillOutPacketIPContext(struct pkt_ctx * pctx,struct iphdr * iph,int ip_len)11376404edcSAsim Jamshed FillOutPacketIPContext(struct pkt_ctx *pctx, struct iphdr *iph, int ip_len)
11476404edcSAsim Jamshed {
11576404edcSAsim Jamshed pctx->p.iph = iph;
11676404edcSAsim Jamshed pctx->p.ip_len = ip_len;
11776404edcSAsim Jamshed
11876404edcSAsim Jamshed return;
11976404edcSAsim Jamshed }
12076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
12176404edcSAsim Jamshed uint8_t *
IPOutputStandalone(struct mtcp_manager * mtcp,uint16_t ip_id,uint32_t saddr,uint32_t daddr,uint16_t tcplen,struct pkt_ctx * pctx,uint32_t cur_ts)12276404edcSAsim Jamshed IPOutputStandalone(struct mtcp_manager *mtcp,
12376404edcSAsim Jamshed uint16_t ip_id, uint32_t saddr, uint32_t daddr, uint16_t tcplen,
12476404edcSAsim Jamshed struct pkt_ctx *pctx, uint32_t cur_ts)
12576404edcSAsim Jamshed {
12676404edcSAsim Jamshed struct iphdr *iph;
12776404edcSAsim Jamshed int nif;
12876404edcSAsim Jamshed unsigned char * haddr;
12976404edcSAsim Jamshed int rc = -1;
13076404edcSAsim Jamshed
13176404edcSAsim Jamshed nif = GetOutputInterface(daddr);
13276404edcSAsim Jamshed if (nif < 0)
13376404edcSAsim Jamshed return NULL;
13476404edcSAsim Jamshed
13576404edcSAsim Jamshed haddr = GetDestinationHWaddr(daddr);
13676404edcSAsim Jamshed if (!haddr) {
13776404edcSAsim Jamshed #ifdef RUN_ARP
13876404edcSAsim Jamshed /* ARP requests will not be created if it's a standalone middlebox */
13976404edcSAsim Jamshed /* tcp will retry sending the packet later */
14076404edcSAsim Jamshed if (!pctx->forward)
14176404edcSAsim Jamshed RequestARP(mtcp, daddr, nif, mtcp->cur_ts);
14276404edcSAsim Jamshed #else
14376404edcSAsim Jamshed uint8_t *da = (uint8_t *)&daddr;
14476404edcSAsim Jamshed TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
14576404edcSAsim Jamshed "is not in ARP table!\n",
14676404edcSAsim Jamshed da[0], da[1], da[2], da[3]);
14776404edcSAsim Jamshed #endif
14876404edcSAsim Jamshed return NULL;
14976404edcSAsim Jamshed }
15076404edcSAsim Jamshed
15176404edcSAsim Jamshed iph = (struct iphdr *)EthernetOutput(mtcp, pctx,
15276404edcSAsim Jamshed ETH_P_IP, nif, haddr, tcplen + IP_HEADER_LEN, cur_ts);
15376404edcSAsim Jamshed if (!iph) {
15476404edcSAsim Jamshed return NULL;
15576404edcSAsim Jamshed }
15676404edcSAsim Jamshed
15776404edcSAsim Jamshed iph->ihl = IP_HEADER_LEN >> 2;
15876404edcSAsim Jamshed iph->version = 4;
15976404edcSAsim Jamshed iph->tos = 0;
16076404edcSAsim Jamshed iph->tot_len = htons(IP_HEADER_LEN + tcplen);
16176404edcSAsim Jamshed iph->id = htons(ip_id);
16276404edcSAsim Jamshed iph->frag_off = htons(0x4000); // no fragmentation
16376404edcSAsim Jamshed iph->ttl = 64;
16476404edcSAsim Jamshed iph->protocol = IPPROTO_TCP;
16576404edcSAsim Jamshed iph->saddr = saddr;
16676404edcSAsim Jamshed iph->daddr = daddr;
16776404edcSAsim Jamshed iph->check = 0;
16876404edcSAsim Jamshed
16976404edcSAsim Jamshed /* offload IP checkum if possible */
17076404edcSAsim Jamshed if (likely(mtcp->iom->dev_ioctl != NULL))
17176404edcSAsim Jamshed rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph);
17276404edcSAsim Jamshed /* otherwise calculate IP checksum in S/W */
17376404edcSAsim Jamshed if (rc == -1)
17476404edcSAsim Jamshed iph->check = ip_fast_csum(iph, iph->ihl);
17576404edcSAsim Jamshed
17676404edcSAsim Jamshed FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN);
17776404edcSAsim Jamshed
17876404edcSAsim Jamshed return (uint8_t *)(iph + 1);
17976404edcSAsim Jamshed }
18076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
18176404edcSAsim Jamshed uint8_t *
IPOutput(struct mtcp_manager * mtcp,tcp_stream * stream,uint16_t tcplen,struct pkt_ctx * pctx,uint32_t cur_ts)18276404edcSAsim Jamshed IPOutput(struct mtcp_manager *mtcp, tcp_stream *stream, uint16_t tcplen,
18376404edcSAsim Jamshed struct pkt_ctx *pctx, uint32_t cur_ts)
18476404edcSAsim Jamshed {
18576404edcSAsim Jamshed struct iphdr *iph;
18676404edcSAsim Jamshed int nif;
18776404edcSAsim Jamshed unsigned char *haddr;
18876404edcSAsim Jamshed int rc = -1;
18976404edcSAsim Jamshed
19076404edcSAsim Jamshed if (stream->sndvar->nif_out >= 0) {
19176404edcSAsim Jamshed nif = stream->sndvar->nif_out;
19276404edcSAsim Jamshed } else {
19376404edcSAsim Jamshed nif = GetOutputInterface(stream->daddr);
19476404edcSAsim Jamshed stream->sndvar->nif_out = nif;
19576404edcSAsim Jamshed }
19676404edcSAsim Jamshed
19776404edcSAsim Jamshed haddr = GetDestinationHWaddr(stream->daddr);
19876404edcSAsim Jamshed if (!haddr) {
19976404edcSAsim Jamshed #ifdef RUN_ARP
20076404edcSAsim Jamshed /* if not found in the arp table, send arp request and return NULL */
20176404edcSAsim Jamshed /* ARP requests will not be created if it's a standalone middlebox */
20276404edcSAsim Jamshed /* tcp will retry sending the packet later */
20376404edcSAsim Jamshed if (!pctx->forward)
20476404edcSAsim Jamshed RequestARP(mtcp, stream->daddr, stream->sndvar->nif_out, mtcp->cur_ts);
20576404edcSAsim Jamshed #else
20676404edcSAsim Jamshed uint8_t *da = (uint8_t *)&stream->daddr;
20776404edcSAsim Jamshed TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
20876404edcSAsim Jamshed "is not in ARP table!\n",
20976404edcSAsim Jamshed da[0], da[1], da[2], da[3]);
21076404edcSAsim Jamshed #endif
21176404edcSAsim Jamshed return NULL;
21276404edcSAsim Jamshed }
21376404edcSAsim Jamshed iph = (struct iphdr *)EthernetOutput(mtcp, pctx, ETH_P_IP,
21476404edcSAsim Jamshed stream->sndvar->nif_out, haddr, tcplen + IP_HEADER_LEN, cur_ts);
21576404edcSAsim Jamshed if (!iph) {
21676404edcSAsim Jamshed return NULL;
21776404edcSAsim Jamshed }
21876404edcSAsim Jamshed
21976404edcSAsim Jamshed iph->ihl = IP_HEADER_LEN >> 2;
22076404edcSAsim Jamshed iph->version = 4;
22176404edcSAsim Jamshed iph->tos = 0;
22276404edcSAsim Jamshed iph->tot_len = htons(IP_HEADER_LEN + tcplen);
22376404edcSAsim Jamshed iph->id = htons(stream->sndvar->ip_id++);
22476404edcSAsim Jamshed iph->frag_off = htons(0x4000); // no fragmentation
22576404edcSAsim Jamshed iph->ttl = 64;
22676404edcSAsim Jamshed iph->protocol = IPPROTO_TCP;
22776404edcSAsim Jamshed iph->saddr = stream->saddr;
22876404edcSAsim Jamshed iph->daddr = stream->daddr;
22976404edcSAsim Jamshed iph->check = 0;
23076404edcSAsim Jamshed
23176404edcSAsim Jamshed /* offload IP checkum if possible */
23276404edcSAsim Jamshed if (likely(mtcp->iom->dev_ioctl != NULL))
23376404edcSAsim Jamshed rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph);
23476404edcSAsim Jamshed /* otherwise calculate IP checksum in S/W */
23576404edcSAsim Jamshed if (rc == -1)
23676404edcSAsim Jamshed iph->check = ip_fast_csum(iph, iph->ihl);
23776404edcSAsim Jamshed
23876404edcSAsim Jamshed FillOutPacketIPContext(pctx, iph, tcplen + IP_HEADER_LEN);
23976404edcSAsim Jamshed
24076404edcSAsim Jamshed return (uint8_t *)(iph + 1);
24176404edcSAsim Jamshed }
242