diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..85ce4c3 --- /dev/null +++ b/.clang-format @@ -0,0 +1,112 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: TopLevelDefinitions +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH + - list_for_each_entry + - list_for_each_entry_safe + - hlist_for_each_entry + - rb_list_foreach + - rb_list_foreach_safe +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 4 +UseTab: Never +... diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9c52e53 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +dist: trusty +sudo: required +language: c +script: + - "pushd ." + - "sudo apt-get -qq update" + - "sudo apt-get install -y libelf-dev linux-headers-$(uname -r)" + - "git clone https://github.com/netmap-unipi/netmap" + - "cd netmap && ./configure --no-drivers && make && sudo make install" + - "popd" + - "pushd ." + - "cd codelab && make" + - "popd" + - "pushd ." + - "cd solutions && make" + - "popd" diff --git a/codelab/Makefile b/codelab/Makefile index cb9a82b..2818168 100644 --- a/codelab/Makefile +++ b/codelab/Makefile @@ -1,4 +1,3 @@ -CC=gcc CFLAGS=-Wall -g -Werror -DSOLUTION PROGS=sink forward swap fe @@ -10,4 +9,4 @@ swap: swap.o fe: fe.o clean: - -rm *.o $(PROGS) + -rm -f *.o $(PROGS) diff --git a/codelab/fe.c b/codelab/fe.c index 66a9625..a806dcd 100644 --- a/codelab/fe.c +++ b/codelab/fe.c @@ -18,16 +18,18 @@ #include #define NETMAP_WITH_LIBS #include -#include +#include +#include +#include #include #include #include -static int stop = 0; +static int stop = 0; static unsigned long long fwdback = 0; -static unsigned long long fwda = 0; -static unsigned long long fwdb = 0; -static unsigned long long tot = 0; +static unsigned long long fwda = 0; +static unsigned long long fwdb = 0; +static unsigned long long tot = 0; static void sigint_handler(int signum) @@ -40,13 +42,13 @@ rx_ready(struct nm_desc *nmd) { unsigned int ri; - for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri ++) { - struct netmap_ring *ring; + for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri++) { + struct netmap_ring *ring; - ring = NETMAP_RXRING(nmd->nifp, ri); - if (nm_ring_space(ring)) { - return 1; /* there is something to read */ - } + ring = NETMAP_RXRING(nmd->nifp, ri); + if (nm_ring_space(ring)) { + return 1; /* there is something to read */ + } } return 0; @@ -56,7 +58,7 @@ static inline int pkt_get_udp_port(const char *buf) { struct ether_header *ethh; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; ethh = (struct ether_header *)buf; @@ -64,18 +66,17 @@ pkt_get_udp_port(const char *buf) /* Filter out non-IP traffic. */ return 0; } - iph = (struct iphdr *)(ethh + 1); - if (iph->protocol != IPPROTO_UDP) { + iph = (struct ip *)(ethh + 1); + if (iph->ip_p != IPPROTO_UDP) { /* Filter out non-UDP traffic. */ return 0; } udph = (struct udphdr *)(iph + 1); /* Return destination port. */ - return ntohs(udph->dest); + return ntohs(udph->uh_dport); } - static void forward_pkts(struct nm_desc *src, struct nm_desc *dst) { @@ -90,8 +91,8 @@ forward_pkts(struct nm_desc *src, struct nm_desc *dst) rxring = NETMAP_RXRING(src->nifp, si); txring = NETMAP_TXRING(dst->nifp, di); - nrx = nm_ring_space(rxring); - ntx = nm_ring_space(txring); + nrx = nm_ring_space(rxring); + ntx = nm_ring_space(txring); if (nrx == 0) { si++; continue; @@ -101,25 +102,25 @@ forward_pkts(struct nm_desc *src, struct nm_desc *dst) continue; } - rxhead = rxring->head; - txhead = txring->head; - for (; nrx > 0 && ntx > 0; - nrx --, rxhead = nm_ring_next(rxring, rxhead), tot ++) { + rxhead = rxring->head; + txhead = txring->head; + for (; nrx > 0 && ntx > 0; + nrx--, rxhead = nm_ring_next(rxring, rxhead), tot++) { struct netmap_slot *rs = &rxring->slot[rxhead]; struct netmap_slot *ts = &txring->slot[txhead]; - char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); - char *txbuf = NETMAP_BUF(txring, ts->buf_idx); + char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); + char *txbuf = NETMAP_BUF(txring, ts->buf_idx); ts->len = rs->len; memcpy(txbuf, rxbuf, ts->len); txhead = nm_ring_next(txring, txhead); - ntx --; - fwdback ++; - tot ++; + ntx--; + fwdback++; + tot++; } /* Update state of netmap ring. */ - rxring->head = rxring->cur = rxhead; - txring->head = txring->cur = txhead; + rxring->head = rxring->cur = rxhead; + txring->head = txring->cur = txhead; } } @@ -134,11 +135,11 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, nmd_one = nm_open(netmap_port_one, NULL, 0, NULL); if (nmd_one == NULL) { if (!errno) { - printf("Failed to nm_open(%s): not a netmap port\n", - netmap_port_one); + printf("Failed to nm_open(%s): not a netmap port\n", + netmap_port_one); } else { - printf("Failed to nm_open(%s): %s\n", netmap_port_one, - strerror(errno)); + printf("Failed to nm_open(%s): %s\n", netmap_port_one, + strerror(errno)); } return -1; } @@ -159,7 +160,7 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, if (nmd_three == NULL) { if (!errno) { printf("Failed to nm_open(%s): not a netmap port\n", - netmap_port_three); + netmap_port_three); } else { printf("Failed to nm_open(%s): %s\n", netmap_port_three, strerror(errno)); @@ -168,7 +169,6 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, } while (!stop) { - /* Forward traffic from ports two and three back to port one. */ forward_pkts(nmd_two, nmd_one); forward_pkts(nmd_three, nmd_one); @@ -191,19 +191,20 @@ usage(char **argv) { printf("usage: %s [-h] [-i NETMAP_PORT_ONE] " "[-i NETMAP_PORT_TWO] [-i NETMAP_PORT_THREE] " - "[-p UDP_PORT_A] [-p UDP_PORT_B]\n", argv[0]); + "[-p UDP_PORT_A] [-p UDP_PORT_B]\n", + argv[0]); exit(EXIT_SUCCESS); } int main(int argc, char **argv) { - const char *netmap_port_one = NULL; - const char *netmap_port_two = NULL; + const char *netmap_port_one = NULL; + const char *netmap_port_two = NULL; const char *netmap_port_three = NULL; int udp_port; - int udp_port_a = 8000; - int udp_port_b = 8001; + int udp_port_a = 8000; + int udp_port_b = 8001; int udp_port_args = 0; struct sigaction sa; int opt; @@ -211,41 +212,41 @@ main(int argc, char **argv) while ((opt = getopt(argc, argv, "hi:p:")) != -1) { switch (opt) { - case 'h': + case 'h': + usage(argv); + return 0; + + case 'i': + if (netmap_port_one == NULL) { + netmap_port_one = optarg; + } else if (netmap_port_two == NULL) { + netmap_port_two = optarg; + } else if (netmap_port_three == NULL) { + netmap_port_three = optarg; + } + break; + + case 'p': + udp_port = atoi(optarg); + if (udp_port <= 0 || udp_port >= 65535) { + printf(" invalid UDP port %s\n", optarg); usage(argv); - return 0; - - case 'i': - if (netmap_port_one == NULL) { - netmap_port_one = optarg; - } else if (netmap_port_two == NULL) { - netmap_port_two = optarg; - } else if (netmap_port_three == NULL) { - netmap_port_three = optarg; - } + } + switch (udp_port_args) { + case 0: + udp_port_a = udp_port; break; - - case 'p': - udp_port = atoi(optarg); - if (udp_port <= 0 || udp_port >= 65535) { - printf(" invalid UDP port %s\n", optarg); - usage(argv); - } - switch (udp_port_args) { - case 0: - udp_port_a = udp_port; - break; - case 1: - udp_port_b = udp_port; - break; - } - udp_port_args ++; + case 1: + udp_port_b = udp_port; break; + } + udp_port_args++; + break; - default: - printf(" unrecognized option '-%c'\n", opt); - usage(argv); - return -1; + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; } } @@ -263,7 +264,7 @@ main(int argc, char **argv) sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - ret = sigaction(SIGINT, &sa, NULL); + ret = sigaction(SIGINT, &sa, NULL); if (ret) { perror("sigaction(SIGINT)"); exit(EXIT_FAILURE); @@ -276,8 +277,10 @@ main(int argc, char **argv) printf("UDP port A: %d\n", udp_port_a); printf("UDP port B: %d\n", udp_port_b); - main_loop(netmap_port_one, netmap_port_two, netmap_port_three, - udp_port_a, udp_port_b); + main_loop(netmap_port_one, netmap_port_two, netmap_port_three, udp_port_a, + udp_port_b); + + (void)pkt_get_udp_port; return 0; } diff --git a/codelab/forward.c b/codelab/forward.c index 2e9c35b..5605072 100644 --- a/codelab/forward.c +++ b/codelab/forward.c @@ -15,12 +15,14 @@ #include #define NETMAP_WITH_LIBS #include -#include +#include +#include +#include #include #include #include -static int stop = 0; +static int stop = 0; static unsigned long long fwd = 0; static unsigned long long tot = 0; @@ -35,13 +37,13 @@ rx_ready(struct nm_desc *nmd) { unsigned int ri; - for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri ++) { - struct netmap_ring *ring; + for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri++) { + struct netmap_ring *ring; - ring = NETMAP_RXRING(nmd->nifp, ri); - if (nm_ring_space(ring)) { - return 1; /* there is something to read */ - } + ring = NETMAP_RXRING(nmd->nifp, ri); + if (nm_ring_space(ring)) { + return 1; /* there is something to read */ + } } return 0; @@ -51,7 +53,7 @@ static inline int pkt_select(const char *buf, int udp_port) { struct ether_header *ethh; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; if (udp_port == 0) { @@ -63,24 +65,24 @@ pkt_select(const char *buf, int udp_port) /* Filter out non-IP traffic. */ return 0; } - iph = (struct iphdr *)(ethh + 1); - if (iph->protocol != IPPROTO_UDP) { + iph = (struct ip *)(ethh + 1); + if (iph->ip_p != IPPROTO_UDP) { /* Filter out non-UDP traffic. */ return 0; } udph = (struct udphdr *)(iph + 1); /* Match the destination port. */ - if (udph->dest != htons(udp_port)) { + if (udph->uh_dport != htons(udp_port)) { return 0; } return 1; } - static int -main_loop(const char *netmap_port_one, const char *netmap_port_two, int udp_port) +main_loop(const char *netmap_port_one, const char *netmap_port_two, + int udp_port) { struct nm_desc *nmd_one; struct nm_desc *nmd_two; @@ -115,18 +117,19 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, int udp_port printf("zerocopy %sabled\n", zerocopy ? "en" : "dis"); while (!stop) { - struct pollfd pfd[2]; - pfd[0].fd = nmd_one->fd; - pfd[0].events = 0; - pfd[1].fd = nmd_two->fd; - pfd[1].events = 0; - /* if port one has RX packets then - * POLLOUT on port two else POLLIN on + struct pollfd pfd[2]; + + pfd[0].fd = nmd_one->fd; + pfd[1].fd = nmd_two->fd; + pfd[0].events = 0; + pfd[1].events = 0; + /* TODO: if port one has RX packets then + * POLLOUT on port two else POLLIN on * port one */ poll(pfd, 2, 1000); - /* try to copy as many packets as possible + /* TODO: try to copy as many packets as possible * from port 1 to port 2 */ } @@ -144,7 +147,8 @@ static void usage(char **argv) { printf("usage: %s [-h] [-p UDP_PORT] [-i NETMAP_PORT_ONE] " - "[-i NETMAP_PORT_TWO]\n", argv[0]); + "[-i NETMAP_PORT_TWO]\n", + argv[0]); exit(EXIT_SUCCESS); } @@ -153,37 +157,37 @@ main(int argc, char **argv) { const char *netmap_port_one = NULL; const char *netmap_port_two = NULL; - int udp_port = 0; /* zero means select everything */ + int udp_port = 0; /* zero means select everything */ struct sigaction sa; int opt; int ret; while ((opt = getopt(argc, argv, "hi:p:")) != -1) { switch (opt) { - case 'h': - usage(argv); - return 0; - - case 'i': - if (netmap_port_one == NULL) { - netmap_port_one = optarg; - } else if (netmap_port_two == NULL) { - netmap_port_two = optarg; - } - break; - - case 'p': - udp_port = atoi(optarg); - if (udp_port < 0 || udp_port >= 65535) { - printf(" invalid UDP port %s\n", optarg); - usage(argv); - } - break; - - default: - printf(" unrecognized option '-%c'\n", opt); + case 'h': + usage(argv); + return 0; + + case 'i': + if (netmap_port_one == NULL) { + netmap_port_one = optarg; + } else if (netmap_port_two == NULL) { + netmap_port_two = optarg; + } + break; + + case 'p': + udp_port = atoi(optarg); + if (udp_port < 0 || udp_port >= 65535) { + printf(" invalid UDP port %s\n", optarg); usage(argv); - return -1; + } + break; + + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; } } @@ -201,7 +205,7 @@ main(int argc, char **argv) sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - ret = sigaction(SIGINT, &sa, NULL); + ret = sigaction(SIGINT, &sa, NULL); if (ret) { perror("sigaction(SIGINT)"); exit(EXIT_FAILURE); @@ -214,5 +218,7 @@ main(int argc, char **argv) main_loop(netmap_port_one, netmap_port_two, udp_port); + (void)pkt_select; /* silence the compiler */ + return 0; } diff --git a/codelab/sink.c b/codelab/sink.c index 222e7d9..fbfb618 100644 --- a/codelab/sink.c +++ b/codelab/sink.c @@ -14,7 +14,9 @@ #include #define NETMAP_WITH_LIBS #include -#include +#include +#include +#include #include #include #include @@ -31,7 +33,7 @@ static inline int udp_port_match(const char *buf, unsigned len, int udp_port) { struct ether_header *ethh; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; ethh = (struct ether_header *)buf; @@ -39,15 +41,15 @@ udp_port_match(const char *buf, unsigned len, int udp_port) /* Filter out non-IP traffic. */ return 0; } - iph = (struct iphdr *)(ethh + 1); - if (iph->protocol != IPPROTO_UDP) { + iph = (struct ip *)(ethh + 1); + if (iph->ip_p != IPPROTO_UDP) { /* Filter out non-UDP traffic. */ return 0; } udph = (struct udphdr *)(iph + 1); /* Match the destination port. */ - if (udph->dest == htons(udp_port)) { + if (udph->uh_dport == htons(udp_port)) { return 1; } @@ -74,33 +76,33 @@ int main(int argc, char **argv) { const char *netmap_port = NULL; - int udp_port = 8000; + int udp_port = 8000; struct sigaction sa; int opt; int ret; while ((opt = getopt(argc, argv, "hi:p:")) != -1) { switch (opt) { - case 'h': + case 'h': + usage(argv); + return 0; + + case 'i': + netmap_port = optarg; + break; + + case 'p': + udp_port = atoi(optarg); + if (udp_port <= 0 || udp_port >= 65535) { + printf(" invalid UDP port %s\n", optarg); usage(argv); - return 0; - - case 'i': - netmap_port = optarg; - break; - - case 'p': - udp_port = atoi(optarg); - if (udp_port <= 0 || udp_port >= 65535) { - printf(" invalid UDP port %s\n", optarg); - usage(argv); - } - break; - - default: - printf(" unrecognized option '-%c'\n", opt); - usage(argv); - return -1; + } + break; + + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; } } @@ -113,7 +115,7 @@ main(int argc, char **argv) sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - ret = sigaction(SIGINT, &sa, NULL); + ret = sigaction(SIGINT, &sa, NULL); if (ret) { perror("sigaction(SIGINT)"); exit(EXIT_FAILURE); @@ -124,5 +126,7 @@ main(int argc, char **argv) main_loop(netmap_port, udp_port); + (void)udp_port_match; /* silence the compiler */ + return 0; } diff --git a/codelab/swap.c b/codelab/swap.c index 8cb5c02..2220dbd 100644 --- a/codelab/swap.c +++ b/codelab/swap.c @@ -15,14 +15,16 @@ #include #define NETMAP_WITH_LIBS #include -#include +#include +#include +#include #include #include #include -static int stop = 0; +static int stop = 0; static unsigned long long swapped = 0; -static unsigned long long tot = 0; +static unsigned long long tot = 0; static void sigint_handler(int signum) @@ -35,13 +37,13 @@ rx_ready(struct nm_desc *nmd) { unsigned int ri; - for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri ++) { - struct netmap_ring *ring; + for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri++) { + struct netmap_ring *ring; - ring = NETMAP_RXRING(nmd->nifp, ri); - if (nm_ring_space(ring)) { - return 1; /* there is something to read */ - } + ring = NETMAP_RXRING(nmd->nifp, ri); + if (nm_ring_space(ring)) { + return 1; /* there is something to read */ + } } return 0; @@ -53,7 +55,7 @@ static inline int pkt_udp_port_swap(char *buf) { struct ether_header *ethh; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; uint16_t tmp; @@ -62,20 +64,19 @@ pkt_udp_port_swap(char *buf) /* Filter out non-IP traffic. */ return 0; } - iph = (struct iphdr *)(ethh + 1); - if (iph->protocol != IPPROTO_UDP) { + iph = (struct ip *)(ethh + 1); + if (iph->ip_p != IPPROTO_UDP) { /* Filter out non-UDP traffic. */ return 0; } - udph = (struct udphdr *)(iph + 1); - tmp = udph->source; - udph->source = udph->dest; - udph->dest = tmp; + udph = (struct udphdr *)(iph + 1); + tmp = udph->uh_sport; + udph->uh_sport = udph->uh_dport; + udph->uh_dport = tmp; return 1; } - static int main_loop(const char *netmap_port_one, const char *netmap_port_two) { @@ -127,7 +128,8 @@ static void usage(char **argv) { printf("usage: %s [-h] [-i NETMAP_PORT_ONE] " - "[-i NETMAP_PORT_TWO]\n", argv[0]); + "[-i NETMAP_PORT_TWO]\n", + argv[0]); exit(EXIT_SUCCESS); } @@ -142,22 +144,22 @@ main(int argc, char **argv) while ((opt = getopt(argc, argv, "hi:p:")) != -1) { switch (opt) { - case 'h': - usage(argv); - return 0; - - case 'i': - if (netmap_port_one == NULL) { - netmap_port_one = optarg; - } else if (netmap_port_two == NULL) { - netmap_port_two = optarg; - } - break; - - default: - printf(" unrecognized option '-%c'\n", opt); - usage(argv); - return -1; + case 'h': + usage(argv); + return 0; + + case 'i': + if (netmap_port_one == NULL) { + netmap_port_one = optarg; + } else if (netmap_port_two == NULL) { + netmap_port_two = optarg; + } + break; + + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; } } @@ -175,7 +177,7 @@ main(int argc, char **argv) sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - ret = sigaction(SIGINT, &sa, NULL); + ret = sigaction(SIGINT, &sa, NULL); if (ret) { perror("sigaction(SIGINT)"); exit(EXIT_FAILURE); @@ -187,5 +189,7 @@ main(int argc, char **argv) main_loop(netmap_port_one, netmap_port_two); + (void)pkt_udp_port_swap; + return 0; } diff --git a/fosdem2019/Makefile b/fosdem2019/Makefile new file mode 100644 index 0000000..4c97e0e --- /dev/null +++ b/fosdem2019/Makefile @@ -0,0 +1,9 @@ +CFLAGS=-Wall -g -Werror -O2 +PROGS=stateless-filter + +all: $(PROGS) + +stateless-filter: stateless-filter.o + +clean: + -rm -f *.o $(PROGS) diff --git a/fosdem2019/README b/fosdem2019/README new file mode 100644 index 0000000..2a3e153 --- /dev/null +++ b/fosdem2019/README @@ -0,0 +1,100 @@ +#### Netmap talk at FOSDEM 2019 #### + +URL: https://fosdem.org/2019/schedule/event/netmap_vnf_development/ + +This file contains step-by-step instructions to run the example. + +Requirements: + - Linux (host) machine with KVM enabled + - QEMU Virtual Machine, running Linux or FreeBSD >= 12.x + +### Step 1: Build, install and load netmap on the host machine + +(host) $ mkdir fosdem2019-netmap +(host) $ cd fosdem2019-netmap +(host) $ git clone https://github.com/luigirizzo/netmap +(host) $ cd netmap +(host) $ ./configure --no-drivers # patched drivers not necessary for this example +(host) $ make && sudo make install +(host) $ sudo insmod netmap.ko +(host) $ cd .. + + +### Step 2: Build and install qemu on the host machine + +(host) $ git clone https://github.com/netmap-unipi/qemu +(host) $ cd qemu +(host) $ ./configure --target-list=x86_64-softmmu --enable-kvm --disable-werror --enable-netmap +(host) $ make && sudo make install +(host) $ cd .. + + +### Step 3: Prepare the VM + +Install netmap in the VM (same as step 1, but inside the VM). +Then, build the example: + +(vm) $ git clone https://github.com/netmap-unipi/netmap-tutorial +(vm) $ cd netmap-tutorial/fosdem2019 +(vm) $ make + + +### Step 4: Close the VM and re-launch it with two netmap pipe ports + +(host) $ sudo qemu-system-x86_64 /path/to/qemu/vm/image.qcow2 -enable-kvm -smp 2 -m 2G -vga std -device e1000,netdev=mgmt,mac=00:AA:BB:CC:0a:99 -netdev user,id=mgmt,hostfwd=tcp::20010-:22 -device ptnet-pci,netdev=data10,mac=00:AA:BB:CC:0a:0a -netdev netmap,ifname=vale1:10}1,id=data10,passthrough=on -device ptnet-pci,netdev=data11,mac=00:AA:BB:CC:0a:0b -netdev netmap,ifname=vale1:10{2,id=data11,passthrough=on + + + +### Step 5: Access the VM and find the two passed-through interfaces + +First, load the netmap module: +(vm) $ sudo insmod netmap + +On Linux, a list of passed-through netmap ports can be obtained in this way: +(vm) $ for if in $(ls /sys/class/net); do ethtool -i $if | grep -qq ptnetmap && echo "ptnetmap if: $if"; done + +Bring the interfaces up, e.g.: +(vm) $ sudo ip link set $if up + +On FreeBSD, just run "ifconfig" and look for "ptnet*" interfaces, e.g.: +(vm) $ sudo ifconfig ptnet0 up +(vm) $ sudo ifconfig ptnet1 up + + +### Step 6: Run the example application + +Run the filter with a rule to pass TCP/UDP traffic towards +10.10.10.0/24, port 7777: + +(vm) $ cd netmap/tutorial/fosdem2019 +(vm) $ sudo ./stateless-filter -e netmap:eth1 -i netmap:eth2 -p 10.10.10.0/24:0:7777 + + +### Step 7: Capture traffic forwarded from the VM + +Receive traffic from the other end of the pipe corresponding the INT +port: +(host) $ sudo pkt-gen -i vale1:10}2 -f rx + + +### Step 8: Inject traffic into the VM + +Send UDP traffic (with matching destination IP and port) into the other +end of the pipe corresponding to the EXT port: + +(host) $ sudo pkt-gen -i vale1:10{1 -f tx -d 10.10.10.23:7777 + + +### More experiments: + +1. Restart the filter, changing the rule to pass only port 80, and check + that no traffic is forwarded: +(vm) $ sudo ./stateless-filter -e netmap:eth1 -i netmap:eth2 -p 10.10.10.0/24:0:80 + +2. Try with bidirectional traffic, replacing "-f tx" with "-f ping", + and "-f rx" with "-f pong". + +3. Add more pass rule or use a pass-any rule ("0.0.0.0/0:0:0"). + +4. Try with destination address and ports in a range +(host) $ sudo pkt-gen -i vale1:10{1 -f tx -d 10.10.10.23:7777-10.10.10.129:7780 diff --git a/fosdem2019/stateless-filter.c b/fosdem2019/stateless-filter.c new file mode 100644 index 0000000..6a17c76 --- /dev/null +++ b/fosdem2019/stateless-filter.c @@ -0,0 +1,457 @@ +/* + * This program forwards packets between two netmap ports, an external + * port (ext) and an internal port (int). Packets flowing from ext to + * int are filtered according to the rules provided through command + * line. Packets flowing from int to ext bypass the filter, and they + * are always forwarded. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define NETMAP_WITH_LIBS +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* You can undef MULTIRING to get the simpler code, which assumes + * that each netmap port has a single RX ring and a single TX ring. */ +#define MULTIRING + +static int stop = 0; +static unsigned long long fwd = 0; +static unsigned long long tot = 0; + +static void +sigint_handler(int signum) +{ + stop = 1; +} + +struct filtrule { + /* All fields are in network order. */ + uint32_t ip_daddr; + uint32_t ip_mask; + uint16_t dport; + uint8_t ip_proto; + uint8_t pad; +}; + +static inline int +pkt_select(const char *buf, struct filtrule *rules, int num_rules) +{ + struct ether_header *ethh; + struct udphdr *udph; + struct ip *iph; + int i; + + ethh = (struct ether_header *)buf; + if (ethh->ether_type != htons(ETHERTYPE_IP)) { + /* Filter out non-IP traffic. */ + return 0; + } + iph = (struct ip *)(ethh + 1); + udph = (struct udphdr *)(iph + 1); + + for (i = 0; i < num_rules; i++) { + struct filtrule *rule = rules + i; + + if ((iph->ip_dst.s_addr & rule->ip_mask) + == rule->ip_daddr && + (!rules->ip_proto || rule->ip_proto == iph->ip_p) && + (!rule->dport || rule->dport == udph->uh_dport)) { + return 1; /* select */ + } + } + + return 0; /* discard */ +} + +static void +forward_pkts(struct nm_desc *src, struct nm_desc *dst, struct filtrule *rules, + int num_rules, int zerocopy) +{ +#ifdef MULTIRING + unsigned int si = src->first_rx_ring; + unsigned int di = dst->first_tx_ring; + + while (si <= src->last_rx_ring && di <= dst->last_tx_ring) { + struct netmap_ring *txring; + struct netmap_ring *rxring; + unsigned int rxhead, txhead; + int nrx, ntx; + + rxring = NETMAP_RXRING(src->nifp, si); + txring = NETMAP_TXRING(dst->nifp, di); + nrx = nm_ring_space(rxring); + ntx = nm_ring_space(txring); + if (nrx == 0) { + si++; + continue; + } + if (ntx == 0) { + di++; + continue; + } + + rxhead = rxring->head; + txhead = txring->head; + for (; nrx > 0 && ntx > 0; + nrx--, rxhead = nm_ring_next(rxring, rxhead), tot++) { + struct netmap_slot *rs = &rxring->slot[rxhead]; + struct netmap_slot *ts = &txring->slot[txhead]; + char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); + + if (rules && !pkt_select(rxbuf, rules, num_rules)) { + continue; /* discard */ + } + + ts->len = rs->len; + if (zerocopy) { + uint32_t idx = ts->buf_idx; + ts->buf_idx = rs->buf_idx; + rs->buf_idx = idx; + /* report the buffer change. */ + ts->flags |= NS_BUF_CHANGED; + rs->flags |= NS_BUF_CHANGED; + } else { + char *txbuf = NETMAP_BUF(txring, ts->buf_idx); + memcpy(txbuf, rxbuf, ts->len); + } + txhead = nm_ring_next(txring, txhead); + ntx--; + fwd++; + } + /* Update the pointers in the netmap rings. */ + rxring->head = rxring->cur = rxhead; + txring->head = txring->cur = txhead; + } +#else /* !MULTIRING */ + struct netmap_ring *txring; + struct netmap_ring *rxring; + unsigned int rxhead, txhead; + + rxring = NETMAP_RXRING(src->nifp, 0); + txring = NETMAP_TXRING(dst->nifp, 0); + + for (rxhead = rxring->head, txhead = txring->head; + rxhead != rxring->tail && txhead != txring->tail; + tot++, rxhead = nm_ring_next(rxring, rxhead)) { + struct netmap_slot *rs = &rxring->slot[rxhead]; + struct netmap_slot *ts = &txring->slot[txhead]; + char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); + + if (rules && !pkt_select(rxbuf, rules, num_rules)) { + continue; /* discard */ + } + + ts->len = rs->len; + if (zerocopy) { + uint32_t idx = ts->buf_idx; + ts->buf_idx = rs->buf_idx; + rs->buf_idx = idx; + /* report the buffer change. */ + ts->flags |= NS_BUF_CHANGED; + rs->flags |= NS_BUF_CHANGED; + } else { + char *txbuf = NETMAP_BUF(txring, ts->buf_idx); + memcpy(txbuf, rxbuf, ts->len); + } + txhead = nm_ring_next(txring, txhead); + fwd++; + } + /* Update the pointers in the netmap rings. */ + rxring->head = rxring->cur = rxhead; + txring->head = txring->cur = txhead; +#endif /* !MULTIRING */ +} + +static inline int +rx_ready(struct nm_desc *nmd) +{ +#ifdef MULTIRING + unsigned int ri; + + for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri++) { + struct netmap_ring *ring; + + ring = NETMAP_RXRING(nmd->nifp, ri); + if (nm_ring_space(ring)) { + return 1; /* there is something to read */ + } + } + + return 0; +#else /* !MULTIRING */ + return nm_ring_space(NETMAP_RXRING(nmd->nifp, 0)); +#endif /* !MULTIRING */ +} + +static int +main_loop(const char *ext_port_name, const char *int_port_name, + struct filtrule *rules, int num_rules, int force_copy) +{ + struct nm_desc *ext_port; + struct nm_desc *int_port; + int zerocopy; + + ext_port = nm_open(ext_port_name, NULL, 0, NULL); + if (ext_port == NULL) { + if (!errno) { + printf("Failed to nm_open(%s): not a netmap port\n", + ext_port_name); + } else { + printf("Failed to nm_open(%s): %s\n", ext_port_name, + strerror(errno)); + } + return -1; + } + + int_port = nm_open(int_port_name, NULL, NM_OPEN_NO_MMAP, ext_port); + if (int_port == NULL) { + if (!errno) { + printf("Failed to nm_open(%s): not a netmap port\n", + int_port_name); + } else { + printf("Failed to nm_open(%s): %s\n", int_port_name, + strerror(errno)); + } + return -1; + } + + /* Check if we can do zerocopy. */ + zerocopy = !force_copy && (ext_port->mem == int_port->mem); + printf("zerocopy %sabled\n", zerocopy ? "en" : "dis"); + + while (!stop) { + struct pollfd pfd[2]; + int ret; + + pfd[0].fd = ext_port->fd; + pfd[1].fd = int_port->fd; + pfd[0].events = 0; + pfd[1].events = 0; + if (!rx_ready(ext_port)) { + /* Ran out of input packets on the first port, we need to + * wait for them. */ + pfd[0].events |= POLLIN; + } else { + /* We have input packets on the first port, let's wait for + * TX ring space in the other port. */ + pfd[1].events |= POLLOUT; + } + if (!rx_ready(int_port)) { + /* Ran out of input packets on the second port, we need to + * wait for them. */ + pfd[1].events |= POLLIN; + } else { + /* We have input packets on the second port, let's wait for + * TX ring space in the other port. */ + pfd[0].events |= POLLOUT; + } + + /* We poll with a timeout to have a chance to break the main loop if + * no packets are coming. */ + ret = poll(pfd, 2, 1000); + if (ret < 0) { + perror("poll()"); + } else if (ret == 0) { + /* Timeout */ + continue; + } + + /* Forward in the two directions. */ + forward_pkts(ext_port, int_port, rules, num_rules, zerocopy); + forward_pkts(int_port, ext_port, NULL, 0, zerocopy); + } + + nm_close(ext_port); + nm_close(int_port); + + printf("Total processed packets: %llu\n", tot); + printf("Forwarded packets : %llu\n", fwd); + printf("Dropped packets : %llu\n", tot - fwd); + + return 0; +} + +static void +usage(char **argv) +{ + printf("usage: %s [-h]\n" + " [-p x.y.z.w/mask:proto:dport (pass rule)] [-p ... ]\n" + " [-i INTERNAL_PORT]\n" + " [-e EXTERNAL_PORT]\n" + " [-c (disable zerocopy if supported)]\n" + "\n" + " Zero or more pass rules can be specified. A zero value for" + " mask, proto or dport means 'any'.\n", + argv[0]); + exit(EXIT_SUCCESS); +} + +int +main(int argc, char **argv) +{ +#define MAXRULES 16 + struct filtrule rules[MAXRULES]; + const char *ext_port_name = NULL; + const char *int_port_name = NULL; + struct sigaction sa; + int force_copy = 0; + int num_rules = 0; + int opt, ret, i; + + while ((opt = getopt(argc, argv, "hi:e:p:c")) != -1) { + switch (opt) { + case 'h': + usage(argv); + return 0; + + case 'i': + int_port_name = optarg; + break; + + case 'e': + ext_port_name = optarg; + break; + + case 'p': { + char *copy = strdup(optarg); + char *ipstr, *maskstr, *protostr, *portstr, *null; + int port, proto, mask; + struct in_addr ip; + int ret; + + assert(copy != NULL); + ipstr = strtok(copy, "/"); + if (!ipstr) { + printf(" invalid -p '%s': no IPv4 found\n", + optarg); + usage(argv); + } + ret = inet_pton(AF_INET, ipstr, &ip); + if (ret <= 0) { + printf(" invalid IPv4 '%s'\n", + ipstr); + usage(argv); + } + + maskstr = strtok(NULL, ":"); + if (!maskstr) { + printf(" invalid -p '%s': no mask found\n", + optarg); + usage(argv); + } + mask = atoi(maskstr); + if (mask < 0 || mask > 31) { + printf(" invalid mask '%s'\n", + maskstr); + usage(argv); + } + + protostr = strtok(NULL, ":"); + if (!protostr) { + printf(" invalid -p '%s': no proto found\n", + optarg); + usage(argv); + } + proto = atoi(protostr); + if (proto < 0 || proto > 255) { + printf(" invalid proto '%s'\n", + protostr); + usage(argv); + } + + portstr = strtok(NULL, ":"); + if (!portstr) { + printf(" invalid -p '%s': no port found\n", + optarg); + usage(argv); + } + port = atoi(portstr); + if (port < 0 || port > (1<<16)-1) { + printf(" invalid port '%s'\n", + portstr); + usage(argv); + } + + null = strtok(NULL, ":"); + if (null) { + printf(" invalid -p '%s': trailing chars\n", + optarg); + usage(argv); + } + free(copy); + + if (num_rules >= MAXRULES) { + printf(" too many rules, bailing out\n"); + exit(EXIT_FAILURE); + } + + rules[num_rules].ip_mask = + (((uint64_t)1ULL << mask) - 1ULL) << (32 - mask); + rules[num_rules].ip_mask = htonl(rules[num_rules].ip_mask); + rules[num_rules].ip_daddr = ip.s_addr & rules[num_rules].ip_mask; + rules[num_rules].ip_proto = proto; + rules[num_rules].dport = htons(port); + num_rules++; + break; + } + + case 'c': + force_copy = 1; + break; + + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; + } + } + + if (ext_port_name == NULL) { + printf(" missing external port\n"); + usage(argv); + } + + if (int_port_name == NULL) { + printf(" missing internal port\n"); + usage(argv); + } + + /* Register Ctrl-C handler. */ + sa.sa_handler = sigint_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + ret = sigaction(SIGINT, &sa, NULL); + if (ret) { + perror("sigaction(SIGINT)"); + exit(EXIT_FAILURE); + } + + printf("External port: %s\n", ext_port_name); + printf("Internal port: %s\n", int_port_name); + printf("Rules:\n"); + for (i = 0; i < num_rules; i++) { + printf(" pass ip_daddr 0x%08x/0x%08x ip_proto %u " + "dport %u\n", + ntohl(rules[i].ip_daddr), ntohl(rules[i].ip_mask), + rules[i].ip_proto, ntohs(rules[i].dport)); + } + + main_loop(ext_port_name, int_port_name, rules, num_rules, force_copy); + + return 0; +} diff --git a/solutions/Makefile b/solutions/Makefile index cb9a82b..2818168 100644 --- a/solutions/Makefile +++ b/solutions/Makefile @@ -1,4 +1,3 @@ -CC=gcc CFLAGS=-Wall -g -Werror -DSOLUTION PROGS=sink forward swap fe @@ -10,4 +9,4 @@ swap: swap.o fe: fe.o clean: - -rm *.o $(PROGS) + -rm -f *.o $(PROGS) diff --git a/solutions/fe.c b/solutions/fe.c index 36b7936..fb6abf5 100644 --- a/solutions/fe.c +++ b/solutions/fe.c @@ -18,16 +18,18 @@ #include #define NETMAP_WITH_LIBS #include -#include +#include +#include +#include #include #include #include -static int stop = 0; +static int stop = 0; static unsigned long long fwdback = 0; -static unsigned long long fwda = 0; -static unsigned long long fwdb = 0; -static unsigned long long tot = 0; +static unsigned long long fwda = 0; +static unsigned long long fwdb = 0; +static unsigned long long tot = 0; static void sigint_handler(int signum) @@ -40,13 +42,13 @@ rx_ready(struct nm_desc *nmd) { unsigned int ri; - for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri ++) { - struct netmap_ring *ring; + for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri++) { + struct netmap_ring *ring; - ring = NETMAP_RXRING(nmd->nifp, ri); - if (nm_ring_space(ring)) { - return 1; /* there is something to read */ - } + ring = NETMAP_RXRING(nmd->nifp, ri); + if (nm_ring_space(ring)) { + return 1; /* there is something to read */ + } } return 0; @@ -56,7 +58,7 @@ static inline int pkt_get_udp_port(const char *buf) { struct ether_header *ethh; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; ethh = (struct ether_header *)buf; @@ -64,15 +66,15 @@ pkt_get_udp_port(const char *buf) /* Filter out non-IP traffic. */ return 0; } - iph = (struct iphdr *)(ethh + 1); - if (iph->protocol != IPPROTO_UDP) { + iph = (struct ip *)(ethh + 1); + if (iph->ip_p != IPPROTO_UDP) { /* Filter out non-UDP traffic. */ return 0; } udph = (struct udphdr *)(iph + 1); /* Return destination port. */ - return ntohs(udph->dest); + return ntohs(udph->uh_dport); } #ifdef SOLUTION @@ -86,7 +88,7 @@ pkt_copy_or_drop(struct nm_desc *dst, const char *buf, unsigned len) if (nm_ring_space(txring)) { struct netmap_slot *ts = &txring->slot[txring->head]; - char *txbuf = NETMAP_BUF(txring, ts->buf_idx); + char *txbuf = NETMAP_BUF(txring, ts->buf_idx); ts->len = len; memcpy(txbuf, buf, len); @@ -110,26 +112,26 @@ route_forward(struct nm_desc *one, struct nm_desc *two, struct nm_desc *three, int nrx; rxring = NETMAP_RXRING(one->nifp, si); - nrx = nm_ring_space(rxring); + nrx = nm_ring_space(rxring); if (nrx == 0) { si++; continue; } - rxhead = rxring->head; + rxhead = rxring->head; for (; nrx > 0; nrx--, rxhead = nm_ring_next(rxring, rxhead)) { struct netmap_slot *rs = &rxring->slot[rxhead]; - char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); - int udp_port = pkt_get_udp_port(rxbuf); + char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); + int udp_port = pkt_get_udp_port(rxbuf); if (udp_port == udp_port_a) { fwda += pkt_copy_or_drop(two, rxbuf, rs->len); } else if (udp_port == udp_port_b) { fwdb += pkt_copy_or_drop(three, rxbuf, rs->len); } - tot ++; + tot++; } - rxring->head = rxring->cur = rxhead; + rxring->head = rxring->cur = rxhead; } } #endif /* SOLUTION */ @@ -148,8 +150,8 @@ forward_pkts(struct nm_desc *src, struct nm_desc *dst) rxring = NETMAP_RXRING(src->nifp, si); txring = NETMAP_TXRING(dst->nifp, di); - nrx = nm_ring_space(rxring); - ntx = nm_ring_space(txring); + nrx = nm_ring_space(rxring); + ntx = nm_ring_space(txring); if (nrx == 0) { si++; continue; @@ -159,25 +161,25 @@ forward_pkts(struct nm_desc *src, struct nm_desc *dst) continue; } - rxhead = rxring->head; - txhead = txring->head; - for (; nrx > 0 && ntx > 0; - nrx --, rxhead = nm_ring_next(rxring, rxhead), tot ++) { + rxhead = rxring->head; + txhead = txring->head; + for (; nrx > 0 && ntx > 0; + nrx--, rxhead = nm_ring_next(rxring, rxhead), tot++) { struct netmap_slot *rs = &rxring->slot[rxhead]; struct netmap_slot *ts = &txring->slot[txhead]; - char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); - char *txbuf = NETMAP_BUF(txring, ts->buf_idx); + char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); + char *txbuf = NETMAP_BUF(txring, ts->buf_idx); ts->len = rs->len; memcpy(txbuf, rxbuf, ts->len); txhead = nm_ring_next(txring, txhead); - ntx --; - fwdback ++; - tot ++; + ntx--; + fwdback++; + tot++; } /* Update state of netmap ring. */ - rxring->head = rxring->cur = rxhead; - txring->head = txring->cur = txhead; + rxring->head = rxring->cur = rxhead; + txring->head = txring->cur = txhead; } } @@ -192,11 +194,11 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, nmd_one = nm_open(netmap_port_one, NULL, 0, NULL); if (nmd_one == NULL) { if (!errno) { - printf("Failed to nm_open(%s): not a netmap port\n", - netmap_port_one); + printf("Failed to nm_open(%s): not a netmap port\n", + netmap_port_one); } else { - printf("Failed to nm_open(%s): %s\n", netmap_port_one, - strerror(errno)); + printf("Failed to nm_open(%s): %s\n", netmap_port_one, + strerror(errno)); } return -1; } @@ -217,7 +219,7 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, if (nmd_three == NULL) { if (!errno) { printf("Failed to nm_open(%s): not a netmap port\n", - netmap_port_three); + netmap_port_three); } else { printf("Failed to nm_open(%s): %s\n", netmap_port_three, strerror(errno)); @@ -231,9 +233,9 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, int ret; int two_ready, three_ready; - pfd[0].fd = nmd_one->fd; - pfd[1].fd = nmd_two->fd; - pfd[2].fd = nmd_three->fd; + pfd[0].fd = nmd_one->fd; + pfd[1].fd = nmd_two->fd; + pfd[2].fd = nmd_three->fd; pfd[0].events = POLLIN; pfd[1].events = 0; pfd[2].events = 0; @@ -242,7 +244,7 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, * line blocking (we don't know in advance which packets are going to * be forwarded where). As a result, unfortunately, we may end dropping * packets. */ - two_ready = rx_ready(nmd_two); + two_ready = rx_ready(nmd_two); three_ready = rx_ready(nmd_three); if (!two_ready) { pfd[1].events |= POLLIN; @@ -268,8 +270,7 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, } /* Route and forward from port one to ports two and three. */ - route_forward(nmd_one, nmd_two, nmd_three, udp_port_a, - udp_port_b); + route_forward(nmd_one, nmd_two, nmd_three, udp_port_a, udp_port_b); #endif /* SOLUTION */ /* Forward traffic from ports two and three back to port one. */ @@ -294,19 +295,20 @@ usage(char **argv) { printf("usage: %s [-h] [-i NETMAP_PORT_ONE] " "[-i NETMAP_PORT_TWO] [-i NETMAP_PORT_THREE] " - "[-p UDP_PORT_A] [-p UDP_PORT_B]\n", argv[0]); + "[-p UDP_PORT_A] [-p UDP_PORT_B]\n", + argv[0]); exit(EXIT_SUCCESS); } int main(int argc, char **argv) { - const char *netmap_port_one = NULL; - const char *netmap_port_two = NULL; + const char *netmap_port_one = NULL; + const char *netmap_port_two = NULL; const char *netmap_port_three = NULL; int udp_port; - int udp_port_a = 8000; - int udp_port_b = 8001; + int udp_port_a = 8000; + int udp_port_b = 8001; int udp_port_args = 0; struct sigaction sa; int opt; @@ -314,41 +316,41 @@ main(int argc, char **argv) while ((opt = getopt(argc, argv, "hi:p:")) != -1) { switch (opt) { - case 'h': + case 'h': + usage(argv); + return 0; + + case 'i': + if (netmap_port_one == NULL) { + netmap_port_one = optarg; + } else if (netmap_port_two == NULL) { + netmap_port_two = optarg; + } else if (netmap_port_three == NULL) { + netmap_port_three = optarg; + } + break; + + case 'p': + udp_port = atoi(optarg); + if (udp_port <= 0 || udp_port >= 65535) { + printf(" invalid UDP port %s\n", optarg); usage(argv); - return 0; - - case 'i': - if (netmap_port_one == NULL) { - netmap_port_one = optarg; - } else if (netmap_port_two == NULL) { - netmap_port_two = optarg; - } else if (netmap_port_three == NULL) { - netmap_port_three = optarg; - } + } + switch (udp_port_args) { + case 0: + udp_port_a = udp_port; break; - - case 'p': - udp_port = atoi(optarg); - if (udp_port <= 0 || udp_port >= 65535) { - printf(" invalid UDP port %s\n", optarg); - usage(argv); - } - switch (udp_port_args) { - case 0: - udp_port_a = udp_port; - break; - case 1: - udp_port_b = udp_port; - break; - } - udp_port_args ++; + case 1: + udp_port_b = udp_port; break; + } + udp_port_args++; + break; - default: - printf(" unrecognized option '-%c'\n", opt); - usage(argv); - return -1; + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; } } @@ -366,7 +368,7 @@ main(int argc, char **argv) sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - ret = sigaction(SIGINT, &sa, NULL); + ret = sigaction(SIGINT, &sa, NULL); if (ret) { perror("sigaction(SIGINT)"); exit(EXIT_FAILURE); @@ -379,8 +381,10 @@ main(int argc, char **argv) printf("UDP port A: %d\n", udp_port_a); printf("UDP port B: %d\n", udp_port_b); - main_loop(netmap_port_one, netmap_port_two, netmap_port_three, - udp_port_a, udp_port_b); + main_loop(netmap_port_one, netmap_port_two, netmap_port_three, udp_port_a, + udp_port_b); + + (void)pkt_get_udp_port; return 0; } diff --git a/solutions/flowgraph-down.sh b/solutions/flowgraph-down.sh index 23a3416..6c83d03 100755 --- a/solutions/flowgraph-down.sh +++ b/solutions/flowgraph-down.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh set -x diff --git a/solutions/flowgraph-up.sh b/solutions/flowgraph-up.sh index 76239b4..376d8ff 100755 --- a/solutions/flowgraph-up.sh +++ b/solutions/flowgraph-up.sh @@ -1,10 +1,10 @@ -#!/bin/bash +#!/bin/sh set -x PIDS="" -sudo pkt-gen -i netmap:pipe{1 -f tx -s 10.0.0.1:7000-10.0.0.1:7010 -d 10.0.0.1:8000-10.0.0.1:8004 &> /dev/null & +sudo pkt-gen -i netmap:pipe{1 -f tx -s 10.0.0.1:7000-10.0.0.1:7010 -d 10.0.0.1:8000-10.0.0.1:8004 2>&1 > /dev/null & PIDS="$PIDS $!" sleep 0.5 sudo ./fe -i netmap:pipe}1 -i netmap:pipe{2 -i netmap:pipe{3 -p 8000 -p 8001 & diff --git a/solutions/forward.c b/solutions/forward.c index ad0fc5d..136d4bf 100644 --- a/solutions/forward.c +++ b/solutions/forward.c @@ -15,12 +15,14 @@ #include #define NETMAP_WITH_LIBS #include -#include +#include +#include +#include #include #include #include -static int stop = 0; +static int stop = 0; static unsigned long long fwd = 0; static unsigned long long tot = 0; @@ -35,13 +37,13 @@ rx_ready(struct nm_desc *nmd) { unsigned int ri; - for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri ++) { - struct netmap_ring *ring; + for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri++) { + struct netmap_ring *ring; - ring = NETMAP_RXRING(nmd->nifp, ri); - if (nm_ring_space(ring)) { - return 1; /* there is something to read */ - } + ring = NETMAP_RXRING(nmd->nifp, ri); + if (nm_ring_space(ring)) { + return 1; /* there is something to read */ + } } return 0; @@ -51,7 +53,7 @@ static inline int pkt_select(const char *buf, int udp_port) { struct ether_header *ethh; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; if (udp_port == 0) { @@ -63,15 +65,15 @@ pkt_select(const char *buf, int udp_port) /* Filter out non-IP traffic. */ return 0; } - iph = (struct iphdr *)(ethh + 1); - if (iph->protocol != IPPROTO_UDP) { + iph = (struct ip *)(ethh + 1); + if (iph->ip_p != IPPROTO_UDP) { /* Filter out non-UDP traffic. */ return 0; } udph = (struct udphdr *)(iph + 1); /* Match the destination port. */ - if (udph->dest != htons(udp_port)) { + if (udph->uh_dport != htons(udp_port)) { return 0; } @@ -80,7 +82,8 @@ pkt_select(const char *buf, int udp_port) #ifdef SOLUTION static void -forward_pkts(struct nm_desc *src, struct nm_desc *dst, int udp_port, int zerocopy) +forward_pkts(struct nm_desc *src, struct nm_desc *dst, int udp_port, + int zerocopy) { unsigned int si = src->first_rx_ring; unsigned int di = dst->first_tx_ring; @@ -93,8 +96,8 @@ forward_pkts(struct nm_desc *src, struct nm_desc *dst, int udp_port, int zerocop rxring = NETMAP_RXRING(src->nifp, si); txring = NETMAP_TXRING(dst->nifp, di); - nrx = nm_ring_space(rxring); - ntx = nm_ring_space(txring); + nrx = nm_ring_space(rxring); + ntx = nm_ring_space(txring); if (nrx == 0) { si++; continue; @@ -104,13 +107,13 @@ forward_pkts(struct nm_desc *src, struct nm_desc *dst, int udp_port, int zerocop continue; } - rxhead = rxring->head; - txhead = txring->head; - for (; nrx > 0 && ntx > 0; - nrx --, rxhead = nm_ring_next(rxring, rxhead), tot ++) { + rxhead = rxring->head; + txhead = txring->head; + for (; nrx > 0 && ntx > 0; + nrx--, rxhead = nm_ring_next(rxring, rxhead), tot++) { struct netmap_slot *rs = &rxring->slot[rxhead]; struct netmap_slot *ts = &txring->slot[txhead]; - char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); + char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); if (!pkt_select(rxbuf, udp_port)) { continue; /* discard */ @@ -119,8 +122,8 @@ forward_pkts(struct nm_desc *src, struct nm_desc *dst, int udp_port, int zerocop ts->len = rs->len; if (zerocopy) { uint32_t idx = ts->buf_idx; - ts->buf_idx = rs->buf_idx; - rs->buf_idx = idx; + ts->buf_idx = rs->buf_idx; + rs->buf_idx = idx; /* report the buffer change. */ ts->flags |= NS_BUF_CHANGED; rs->flags |= NS_BUF_CHANGED; @@ -129,18 +132,19 @@ forward_pkts(struct nm_desc *src, struct nm_desc *dst, int udp_port, int zerocop memcpy(txbuf, rxbuf, ts->len); } txhead = nm_ring_next(txring, txhead); - ntx --; - fwd ++; + ntx--; + fwd++; } /* Update state of netmap ring. */ - rxring->head = rxring->cur = rxhead; - txring->head = txring->cur = txhead; + rxring->head = rxring->cur = rxhead; + txring->head = txring->cur = txhead; } } #endif /* SOLUTION */ static int -main_loop(const char *netmap_port_one, const char *netmap_port_two, int udp_port) +main_loop(const char *netmap_port_one, const char *netmap_port_two, + int udp_port) { struct nm_desc *nmd_one; struct nm_desc *nmd_two; @@ -179,8 +183,8 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two, int udp_port struct pollfd pfd[2]; int ret; - pfd[0].fd = nmd_one->fd; - pfd[1].fd = nmd_two->fd; + pfd[0].fd = nmd_one->fd; + pfd[1].fd = nmd_two->fd; pfd[0].events = 0; pfd[1].events = 0; if (!rx_ready(nmd_one)) { @@ -231,7 +235,8 @@ static void usage(char **argv) { printf("usage: %s [-h] [-p UDP_PORT] [-i NETMAP_PORT_ONE] " - "[-i NETMAP_PORT_TWO]\n", argv[0]); + "[-i NETMAP_PORT_TWO]\n", + argv[0]); exit(EXIT_SUCCESS); } @@ -240,37 +245,37 @@ main(int argc, char **argv) { const char *netmap_port_one = NULL; const char *netmap_port_two = NULL; - int udp_port = 0; /* zero means select everything */ + int udp_port = 0; /* zero means select everything */ struct sigaction sa; int opt; int ret; while ((opt = getopt(argc, argv, "hi:p:")) != -1) { switch (opt) { - case 'h': - usage(argv); - return 0; - - case 'i': - if (netmap_port_one == NULL) { - netmap_port_one = optarg; - } else if (netmap_port_two == NULL) { - netmap_port_two = optarg; - } - break; - - case 'p': - udp_port = atoi(optarg); - if (udp_port < 0 || udp_port >= 65535) { - printf(" invalid UDP port %s\n", optarg); - usage(argv); - } - break; - - default: - printf(" unrecognized option '-%c'\n", opt); + case 'h': + usage(argv); + return 0; + + case 'i': + if (netmap_port_one == NULL) { + netmap_port_one = optarg; + } else if (netmap_port_two == NULL) { + netmap_port_two = optarg; + } + break; + + case 'p': + udp_port = atoi(optarg); + if (udp_port < 0 || udp_port >= 65535) { + printf(" invalid UDP port %s\n", optarg); usage(argv); - return -1; + } + break; + + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; } } @@ -288,7 +293,7 @@ main(int argc, char **argv) sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - ret = sigaction(SIGINT, &sa, NULL); + ret = sigaction(SIGINT, &sa, NULL); if (ret) { perror("sigaction(SIGINT)"); exit(EXIT_FAILURE); @@ -301,5 +306,7 @@ main(int argc, char **argv) main_loop(netmap_port_one, netmap_port_two, udp_port); + (void)pkt_select; /* silence the compiler */ + return 0; } diff --git a/solutions/sink.c b/solutions/sink.c index fbf0db4..fddd852 100644 --- a/solutions/sink.c +++ b/solutions/sink.c @@ -14,7 +14,9 @@ #include #define NETMAP_WITH_LIBS #include -#include +#include +#include +#include #include #include #include @@ -31,7 +33,7 @@ static inline int udp_port_match(const char *buf, unsigned len, int udp_port) { struct ether_header *ethh; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; ethh = (struct ether_header *)buf; @@ -39,15 +41,15 @@ udp_port_match(const char *buf, unsigned len, int udp_port) /* Filter out non-IP traffic. */ return 0; } - iph = (struct iphdr *)(ethh + 1); - if (iph->protocol != IPPROTO_UDP) { + iph = (struct ip *)(ethh + 1); + if (iph->ip_p != IPPROTO_UDP) { /* Filter out non-UDP traffic. */ return 0; } udph = (struct udphdr *)(iph + 1); /* Match the destination port. */ - if (udph->dest == htons(udp_port)) { + if (udph->uh_dport == htons(udp_port)) { return 1; } @@ -67,8 +69,7 @@ main_loop(const char *netmap_port, int udp_port) if (!errno) { printf("Failed to nm_open(%s): not a netmap port\n", netmap_port); } else { - printf("Failed to nm_open(%s): %s\n", netmap_port, - strerror(errno)); + printf("Failed to nm_open(%s): %s\n", netmap_port, strerror(errno)); } return -1; } @@ -80,7 +81,7 @@ main_loop(const char *netmap_port, int udp_port) unsigned int ri; int ret; - pfd[0].fd = nmd->fd; + pfd[0].fd = nmd->fd; pfd[0].events = POLLIN; /* We poll with a timeout to have a chance to break the main loop if @@ -94,25 +95,25 @@ main_loop(const char *netmap_port, int udp_port) } /* Scan all the receive rings. */ - for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri ++) { + for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri++) { struct netmap_ring *rxring; unsigned head, tail; int batch; rxring = NETMAP_RXRING(nmd->nifp, ri); - head = rxring->head; - tail = rxring->tail; - batch = tail - head; + head = rxring->head; + tail = rxring->tail; + batch = tail - head; if (batch < 0) { batch += rxring->num_slots; } tot += batch; for (; head != tail; head = nm_ring_next(rxring, head)) { struct netmap_slot *slot = rxring->slot + head; - char *buf = NETMAP_BUF(rxring, slot->buf_idx); + char *buf = NETMAP_BUF(rxring, slot->buf_idx); if (udp_port_match(buf, slot->len, udp_port)) { - cnt ++; + cnt++; } } rxring->cur = rxring->head = head; @@ -140,33 +141,33 @@ int main(int argc, char **argv) { const char *netmap_port = NULL; - int udp_port = 8000; + int udp_port = 8000; struct sigaction sa; int opt; int ret; while ((opt = getopt(argc, argv, "hi:p:")) != -1) { switch (opt) { - case 'h': + case 'h': + usage(argv); + return 0; + + case 'i': + netmap_port = optarg; + break; + + case 'p': + udp_port = atoi(optarg); + if (udp_port <= 0 || udp_port >= 65535) { + printf(" invalid UDP port %s\n", optarg); usage(argv); - return 0; - - case 'i': - netmap_port = optarg; - break; - - case 'p': - udp_port = atoi(optarg); - if (udp_port <= 0 || udp_port >= 65535) { - printf(" invalid UDP port %s\n", optarg); - usage(argv); - } - break; + } + break; - default: - printf(" unrecognized option '-%c'\n", opt); - usage(argv); - return -1; + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; } } @@ -179,7 +180,7 @@ main(int argc, char **argv) sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - ret = sigaction(SIGINT, &sa, NULL); + ret = sigaction(SIGINT, &sa, NULL); if (ret) { perror("sigaction(SIGINT)"); exit(EXIT_FAILURE); @@ -190,5 +191,7 @@ main(int argc, char **argv) main_loop(netmap_port, udp_port); + (void)udp_port_match; /* silence the compiler */ + return 0; } diff --git a/solutions/swap.c b/solutions/swap.c index 5769734..6cbcc1a 100644 --- a/solutions/swap.c +++ b/solutions/swap.c @@ -15,14 +15,16 @@ #include #define NETMAP_WITH_LIBS #include -#include +#include +#include +#include #include #include #include -static int stop = 0; +static int stop = 0; static unsigned long long swapped = 0; -static unsigned long long tot = 0; +static unsigned long long tot = 0; static void sigint_handler(int signum) @@ -35,13 +37,13 @@ rx_ready(struct nm_desc *nmd) { unsigned int ri; - for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri ++) { - struct netmap_ring *ring; + for (ri = nmd->first_rx_ring; ri <= nmd->last_rx_ring; ri++) { + struct netmap_ring *ring; - ring = NETMAP_RXRING(nmd->nifp, ri); - if (nm_ring_space(ring)) { - return 1; /* there is something to read */ - } + ring = NETMAP_RXRING(nmd->nifp, ri); + if (nm_ring_space(ring)) { + return 1; /* there is something to read */ + } } return 0; @@ -53,7 +55,7 @@ static inline int pkt_udp_port_swap(char *buf) { struct ether_header *ethh; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; uint16_t tmp; @@ -62,15 +64,15 @@ pkt_udp_port_swap(char *buf) /* Filter out non-IP traffic. */ return 0; } - iph = (struct iphdr *)(ethh + 1); - if (iph->protocol != IPPROTO_UDP) { + iph = (struct ip *)(ethh + 1); + if (iph->ip_p != IPPROTO_UDP) { /* Filter out non-UDP traffic. */ return 0; } - udph = (struct udphdr *)(iph + 1); - tmp = udph->source; - udph->source = udph->dest; - udph->dest = tmp; + udph = (struct udphdr *)(iph + 1); + tmp = udph->uh_sport; + udph->uh_sport = udph->uh_dport; + udph->uh_dport = tmp; return 1; } @@ -90,8 +92,8 @@ swap_and_forward(struct nm_desc *src, struct nm_desc *dst, int zerocopy) rxring = NETMAP_RXRING(src->nifp, si); txring = NETMAP_TXRING(dst->nifp, di); - nrx = nm_ring_space(rxring); - ntx = nm_ring_space(txring); + nrx = nm_ring_space(rxring); + ntx = nm_ring_space(txring); if (nrx == 0) { si++; continue; @@ -101,9 +103,9 @@ swap_and_forward(struct nm_desc *src, struct nm_desc *dst, int zerocopy) continue; } - rxhead = rxring->head; - txhead = txring->head; - for (; nrx > 0 && ntx > 0; nrx--, ntx--, tot++) { + rxhead = rxring->head; + txhead = txring->head; + for (; nrx > 0 && ntx > 0; nrx--, ntx--, tot++) { struct netmap_slot *rs = &rxring->slot[rxhead]; struct netmap_slot *ts = &txring->slot[txhead]; char *txbuf; @@ -111,15 +113,15 @@ swap_and_forward(struct nm_desc *src, struct nm_desc *dst, int zerocopy) ts->len = rs->len; if (zerocopy) { uint32_t idx = ts->buf_idx; - ts->buf_idx = rs->buf_idx; - rs->buf_idx = idx; + ts->buf_idx = rs->buf_idx; + rs->buf_idx = idx; /* report the buffer change. */ ts->flags |= NS_BUF_CHANGED; rs->flags |= NS_BUF_CHANGED; txbuf = NETMAP_BUF(txring, ts->buf_idx); } else { char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx); - txbuf = NETMAP_BUF(txring, ts->buf_idx); + txbuf = NETMAP_BUF(txring, ts->buf_idx); memcpy(txbuf, rxbuf, ts->len); } @@ -128,8 +130,8 @@ swap_and_forward(struct nm_desc *src, struct nm_desc *dst, int zerocopy) rxhead = nm_ring_next(rxring, rxhead); } /* Update state of netmap ring. */ - rxring->head = rxring->cur = rxhead; - txring->head = txring->cur = txhead; + rxring->head = rxring->cur = rxhead; + txring->head = txring->cur = txhead; } } #endif /* SOLUTION */ @@ -174,8 +176,8 @@ main_loop(const char *netmap_port_one, const char *netmap_port_two) struct pollfd pfd[2]; int ret; - pfd[0].fd = nmd_one->fd; - pfd[1].fd = nmd_two->fd; + pfd[0].fd = nmd_one->fd; + pfd[1].fd = nmd_two->fd; pfd[0].events = 0; pfd[1].events = 0; if (!rx_ready(nmd_one)) { @@ -226,7 +228,8 @@ static void usage(char **argv) { printf("usage: %s [-h] [-i NETMAP_PORT_ONE] " - "[-i NETMAP_PORT_TWO]\n", argv[0]); + "[-i NETMAP_PORT_TWO]\n", + argv[0]); exit(EXIT_SUCCESS); } @@ -241,22 +244,22 @@ main(int argc, char **argv) while ((opt = getopt(argc, argv, "hi:p:")) != -1) { switch (opt) { - case 'h': - usage(argv); - return 0; - - case 'i': - if (netmap_port_one == NULL) { - netmap_port_one = optarg; - } else if (netmap_port_two == NULL) { - netmap_port_two = optarg; - } - break; - - default: - printf(" unrecognized option '-%c'\n", opt); - usage(argv); - return -1; + case 'h': + usage(argv); + return 0; + + case 'i': + if (netmap_port_one == NULL) { + netmap_port_one = optarg; + } else if (netmap_port_two == NULL) { + netmap_port_two = optarg; + } + break; + + default: + printf(" unrecognized option '-%c'\n", opt); + usage(argv); + return -1; } } @@ -274,7 +277,7 @@ main(int argc, char **argv) sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - ret = sigaction(SIGINT, &sa, NULL); + ret = sigaction(SIGINT, &sa, NULL); if (ret) { perror("sigaction(SIGINT)"); exit(EXIT_FAILURE); @@ -286,5 +289,7 @@ main(int argc, char **argv) main_loop(netmap_port_one, netmap_port_two); + (void)pkt_udp_port_swap; + return 0; }