xref: /mOS-networking-stack/core/src/ip_out.c (revision 05e3289c)
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