Commit c17fd5db authored by Jialin Li's avatar Jialin Li
Browse files

tofino: add tofino adapter

parent 8bd1069a
......@@ -13,6 +13,7 @@ sims/nic/i40e_bm/i40e_bm
sims/net/wire/net_wire
sims/net/tap/net_tap
sims/net/switch/net_switch
sims/tofino/tofino
doc/doxygen
doc/_build
images/kernel/kheaders/
......
......@@ -25,5 +25,6 @@ include mk/subdir_pre.mk
$(eval $(call subdir,external))
$(eval $(call subdir,net))
$(eval $(call subdir,nic))
$(eval $(call subdir,tofino))
include mk/subdir_post.mk
# Copyright 2021 Max Planck Institute for Software Systems, and
# National University of Singapore
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
include mk/subdir_pre.mk
bin_tofino = $(d)tofino
OBJS := $(d)tofino.o
$(OBJS): CPPFLAGS := $(CPPFLAGS) -I$(d)include/
$(bin_tofino): $(OBJS) $(lib_netif)
CLEAN := $(bin_tofino) $(OBJS)
ALL := $(bin_tofino)
include mk/subdir_post.mk
/*
* Copyright 2021 Max Planck Institute for Software Systems, and
* National University of Singapore
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <csignal>
#include <cstdio>
#include <cstring>
#include <climits>
#include <cassert>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <vector>
extern "C" {
#include <simbricks/netif/netif.h>
#include <simbricks/proto/base.h>
};
static uint64_t sync_period = (500 * 1000ULL);
static uint64_t eth_latency = (500 * 1000ULL); // 500ns
static const int ETHER_TYPE = 0x0800;
static uint64_t cur_ts = 0;
static int exiting = 0;
static std::vector<struct SimbricksNetIf> nsifs;
static std::vector<int> tofino_fds;
static void sigint_handler(int dummy) {
exiting = 1;
}
static void dev_to_switch(struct SimbricksNetIf *nsif, size_t port) {
volatile union SimbricksProtoNetD2N *msg_from =
SimbricksNetIfD2NPoll(nsif, cur_ts);
if (msg_from == nullptr) {
return;
}
uint8_t type = msg_from->dummy.own_type & SIMBRICKS_PROTO_NET_D2N_MSG_MASK;
if (type == SIMBRICKS_PROTO_NET_D2N_MSG_SEND) {
volatile struct SimbricksProtoNetD2NSend *tx;
tx = &msg_from->send;
if (send(tofino_fds.at(port), (const void *)tx->data, tx->len, 0) < tx->len) {
fprintf(stderr, "tofino: failed to forward packet to switch\n");
abort();
}
} else if (type == SIMBRICKS_PROTO_NET_D2N_MSG_SYNC) {
} else {
fprintf(stderr, "tofino: unsupported type=%u\n", type);
abort();
}
SimbricksNetIfD2NDone(nsif, msg_from);
}
static void switch_to_dev(size_t port) {
static const int BUFFER_SIZE = 2048;
char buf[BUFFER_SIZE];
volatile union SimbricksProtoNetN2D *msg_to;
ssize_t n = recv(tofino_fds.at(port), buf, BUFFER_SIZE, 0);
if (n <= 0) {
return;
}
msg_to = SimbricksNetIfN2DAlloc(&nsifs[port], cur_ts, eth_latency);
if (msg_to != NULL) {
volatile struct SimbricksProtoNetN2DRecv *rx;
rx = &msg_to->recv;
rx->len = n;
rx->port = 0;
memcpy((void *)rx->data, (void *)buf, n);
// WMB();
rx->own_type =
SIMBRICKS_PROTO_NET_N2D_MSG_RECV | SIMBRICKS_PROTO_NET_N2D_OWN_DEV;
} else {
fprintf(stderr, "switch_to_dev: dropping packet\n");
}
}
int main(int argc, char *argv[]) {
int c;
int bad_option = 0;
int sync_mode = SIMBRICKS_PROTO_SYNC_SIMBRICKS;
int sync = 1;
struct SimbricksNetIf nsif;
// Parse command line argument
while ((c = getopt(argc, argv, "s:S:E:m:")) != -1 && !bad_option) {
switch (c) {
case 's':
if (SimbricksNetIfInit(&nsif, optarg, &sync) != 0) {
fprintf(stderr, "connecting to %s failed\n", optarg);
return EXIT_FAILURE;
}
nsifs.push_back(nsif);
break;
case 'S':
sync_period = strtoull(optarg, NULL, 0) * 1000ULL;
break;
case 'E':
eth_latency = strtoull(optarg, NULL, 0) * 1000ULL;
break;
case 'm':
sync_mode = strtol(optarg, NULL, 0);
assert(sync_mode == SIMBRICKS_PROTO_SYNC_SIMBRICKS ||
sync_mode == SIMBRICKS_PROTO_SYNC_BARRIER);
break;
default:
fprintf(stderr, "unknown option %c\n", c);
bad_option = 1;
break;
}
}
if (nsifs.empty() || bad_option) {
fprintf(stderr,
"Usage: tofino [-S SYNC-PERIOD] [-E ETH-LATENCY] "
"-s SOCKET-A [-s SOCKET-B ...]\n");
return EXIT_FAILURE;
}
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler);
// Create sockets for Tofino model interfaces
for (size_t port = 0; port < nsifs.size(); port++) {
int fd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE));
if (fd == -1) {
fprintf(stderr, "Failed to create raw socket\n");
abort();
}
char ifname[16];
sprintf(ifname, "veth%ld", port*2);
struct ifreq ifopts;
memset(&ifopts, 0, sizeof(ifopts));
strcpy(ifopts.ifr_name, ifname);
if (ioctl(fd, SIOCGIFINDEX, &ifopts) < 0) {
fprintf(stderr, "Failed to set ioctl option SIOCGIFINDEX\n");
abort();
}
int sockopt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) == -1) {
fprintf(stderr, "Failed to set socket option SO_REUSEADDR");
abort();
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
fprintf(stderr, "Failed to set socket to non-blocking\n");
abort();
}
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifopts.ifr_ifindex;
if (bind(fd, (struct sockaddr *)&sll, sizeof(sll)) == -1) {
fprintf(stderr, "Failed to bind socket\n");
abort();
}
tofino_fds.push_back(fd);
}
printf("start polling\n");
while (!exiting) {
// Sync all interfaces
for (auto &nsif : nsifs) {
if (SimbricksNetIfN2DSync(&nsif, cur_ts, eth_latency, sync_period,
sync_mode) != 0) {
fprintf(stderr, "SimbricksNetIfN2DSync failed\n");
abort();
}
}
SimbricksNetIfAdvanceEpoch(cur_ts, sync_period, sync_mode);
// Switch packets
uint64_t min_ts;
do {
min_ts = ULLONG_MAX;
for (size_t port = 0; port < nsifs.size(); port++) {
auto &nsif = nsifs.at(port);
dev_to_switch(&nsif, port);
if (nsif.sync) {
uint64_t ts = SimbricksNetIfD2NTimestamp(&nsif);
min_ts = ts < min_ts ? ts : min_ts;
}
}
for (size_t port = 0; port < nsifs.size(); port++) {
switch_to_dev(port);
}
} while (!exiting && (min_ts <= cur_ts));
// Update cur_ts
if (min_ts < ULLONG_MAX) {
cur_ts = SimbricksNetIfAdvanceTime(min_ts, sync_period, sync_mode);
}
}
for (int fd : tofino_fds) {
close(fd);
}
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment