From: claudio Date: Thu, 11 Nov 2021 09:59:19 +0000 (+0000) Subject: Retire switchd and switchctl. While interesting they never managed to X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=63686bc14b0d7232e078ecc1542dfd20ecf54d8a;p=openbsd Retire switchd and switchctl. While interesting they never managed to really get into a usable state. The OpenFlow API is mostly superseeded by P4 and so this is a bit of a dead end. OK akoshibe@ yasuoka@ deraadt@ kn@ patrick@ sthen@ --- diff --git a/usr.sbin/switchctl/Makefile b/usr.sbin/switchctl/Makefile deleted file mode 100644 index d6007e91b3f..00000000000 --- a/usr.sbin/switchctl/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# $OpenBSD: Makefile,v 1.5 2017/07/06 12:15:23 espie Exp $ - -SWITCHD= ${.CURDIR}/../switchd - -.PATH: ${SWITCHD} - -PROG= switchctl -MAN= switchctl.8 -SRCS= log.c ofpclient.c parser.c util.c imsg_util.c switchctl.c -SRCS+= ofp10.c ofp13.c ofp_common.c packet.c - -LDADD= -lutil -DPADD= ${LIBUTIL} - -CFLAGS+= -Wall -I${.CURDIR} -I${SWITCHD} -CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes -CFLAGS+= -Wmissing-declarations -CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual -CFLAGS+= -Wsign-compare - -GENERATED= ofp_map.c ofp10_map.c -SRCS+= ${GENERATED} -CLEANFILES+= ${GENERATED} - -ofp_map.c: genmap.sh ${SWITCHD}/ofp_map.h ${SWITCHD}/../../sys/net/ofp.h - /bin/sh ${SWITCHD}/genmap.sh -i ${SWITCHD}/../../sys/net/ofp.h -t ofp \ - -m ${SWITCHD}/ofp_map.h -h '' > $@ - @touch $@ - -ofp10_map.c: genmap.sh ${SWITCHD}/ofp_map.h ${SWITCHD}/ofp10.h - /bin/sh ${SWITCHD}/genmap.sh -i ${SWITCHD}/ofp10.h -t ofp10 \ - -m ${SWITCHD}/ofp_map.h -h '"ofp10.h"' > $@ - @touch $@ - -.include diff --git a/usr.sbin/switchctl/ofpclient.c b/usr.sbin/switchctl/ofpclient.c deleted file mode 100644 index b349a0ba842..00000000000 --- a/usr.sbin/switchctl/ofpclient.c +++ /dev/null @@ -1,304 +0,0 @@ -/* $OpenBSD: ofpclient.c,v 1.7 2018/10/21 21:10:24 akoshibe Exp $ */ - -/* - * Copyright (c) 2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" -#include "parser.h" - -void ofpclient_read(struct switch_connection *, int); -int flowmod(struct switchd *, struct switch_connection *, - struct parse_result *); -int flowmod_test(struct switchd *, struct switch_connection *); - -void -ofpclient(struct parse_result *res, struct passwd *pw) -{ - struct switch_connection con; - struct switchd sc; - int s, timeout; - struct sockaddr_un *un; - - memset(&sc, 0, sizeof(sc)); - sc.sc_tap = -1; - - /* If no uri has been specified, try to connect to localhost */ - if (res->uri.swa_addr.ss_family == AF_UNSPEC) { - res->uri.swa_type = SWITCH_CONN_TCP; - if (parsehostport("127.0.0.1", - (struct sockaddr *)&res->uri.swa_addr, - sizeof(res->uri.swa_addr)) != 0) - fatal("could not parse address"); - } - - memset(&con, 0, sizeof(con)); - memcpy(&con.con_peer, &res->uri.swa_addr, sizeof(res->uri.swa_addr)); - con.con_sc = ≻ - - /* - * Connect and send the request - */ - switch (res->uri.swa_type) { - case SWITCH_CONN_TCP: - if ((s = socket(res->uri.swa_addr.ss_family, SOCK_STREAM, - IPPROTO_TCP)) == -1) - fatal("socket"); - - /* Use the default port if no port has been specified */ - if (socket_getport(&con.con_peer) == 0) - (void)socket_setport(&con.con_peer, SWITCHD_CTLR_PORT); - - if (connect(s, (struct sockaddr *)&con.con_peer, - con.con_peer.ss_len) == -1) - fatal("connect"); - - con.con_fd = s; - break; - case SWITCH_CONN_LOCAL: - un = (struct sockaddr_un *)&res->uri.swa_addr; - - if (strncmp(un->sun_path, "/dev/switch", - strlen("/dev/switch")) != 0) - fatalx("device path not supported"); - - if ((s = open(un->sun_path, O_RDWR | O_NONBLOCK)) == -1) - fatalx("failed to open %s", un->sun_path); - con.con_fd = s; - break; - default: - fatalx("connect type not supported"); - } - - /* Drop privileges */ - if (pledge("stdio", NULL) == -1) - err(1, "pledge"); - - /* Set a default read timeout */ - timeout = 3 * 1000; - - log_setverbose(res->verbose); - - ofp_send_hello(&sc, &con, OFP_V_1_3); - ofpclient_read(&con, timeout); - - log_setverbose(res->quiet ? res->verbose : 2); - - switch (res->action) { - case DUMP_DESC: - ofp13_desc(&sc, &con); - break; - case DUMP_FEATURES: - ofp_send_featuresrequest(&sc, &con); - break; - case DUMP_FLOWS: - ofp13_flow_stats(&sc, &con, OFP_PORT_ANY, OFP_GROUP_ID_ANY, - res->table); - break; - case DUMP_TABLES: - ofp13_table_features(&sc, &con, res->table); - break; - case FLOW_ADD: - case FLOW_DELETE: - case FLOW_MODIFY: - timeout = 0; - flowmod(&sc, &con, res); - break; - default: - fatalx("unsupported action"); - } - - /* XXX */ - ofpclient_read(&con, timeout); -} - -int -flowmod(struct switchd *sc, struct switch_connection *con, - struct parse_result *res) -{ - struct ofp_header *oh; - struct ofp_flow_mod *fm; - - if (oflowmod_iclose(&res->fctx) == -1) - goto err; - if (oflowmod_close(&res->fctx) == -1) - goto err; - - fm = res->fctx.ctx_fm; - fm->fm_table_id = res->table; - oh = &fm->fm_oh; - - if (ofp_validate(sc, &con->con_local, &con->con_peer, - oh, res->fbuf, oh->oh_version) != 0) - goto err; - - ofrelay_write(con, res->fbuf); - - return (0); - - err: - (void)oflowmod_err(&res->fctx, __func__, __LINE__); - log_warnx("invalid flow"); - return (-1); -} - -void -ofpclient_read(struct switch_connection *con, int timeout) -{ - uint8_t rbuf[0xffff]; - ssize_t rlen; - struct ofp_header *oh; - struct ibuf *ibuf; - struct pollfd pfd[1]; - int nfds; - - /* Wait for response */ - pfd[0].fd = con->con_fd; - pfd[0].events = POLLIN; - nfds = poll(pfd, 1, timeout); - if (nfds == -1 || (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))) - fatal("poll error"); - if (nfds == 0) { - if (timeout) - fatal("time out"); - return; - } - - if ((rlen = read(con->con_fd, rbuf, sizeof(rbuf))) == -1) - fatal("read"); - if (rlen == 0) - fatal("connection closed"); - - if ((ibuf = ibuf_new(rbuf, rlen)) == NULL) - fatal("ibuf_new"); - - if ((oh = ibuf_seek(ibuf, 0, sizeof(*oh))) == NULL) - fatal("short header"); - - if (ofp_validate(con->con_sc, - &con->con_peer, &con->con_local, oh, ibuf, oh->oh_version) != 0) - fatal("ofp_validate"); - - if (con->con_state == OFP_STATE_CLOSED) { - con->con_version = oh->oh_version; - ofp_recv_hello(con->con_sc, con, oh, ibuf); - con->con_state = OFP_STATE_ESTABLISHED; - } - - ibuf_free(ibuf); -} - -/* - * stubs for ofp*.c - */ - -void -ofrelay_write(struct switch_connection *con, struct ibuf *buf) -{ - struct msgbuf msgbuf; - - msgbuf_init(&msgbuf); - msgbuf.fd = con->con_fd; - - ibuf_close(&msgbuf, buf); - ibuf_write(&msgbuf); -} - -struct switch_control * -switch_add(struct switch_connection *con) -{ - static struct switch_control sw; - con->con_switch = &sw; - return (&sw); -} - -struct macaddr * -switch_learn(struct switchd *sc, struct switch_control *sw, - uint8_t *ea, uint32_t port) -{ - return (NULL); -} - -struct macaddr * -switch_cached(struct switch_control *sw, uint8_t *ea) -{ - return (NULL); -} - -int -ofp_nextstate(struct switchd *sc, struct switch_connection *con, - enum ofp_state state) -{ - int rv = 0; - - switch (con->con_state) { - case OFP_STATE_CLOSED: - if (state != OFP_STATE_HELLO_WAIT) - return (-1); - break; - - case OFP_STATE_HELLO_WAIT: - if (state != OFP_STATE_FEATURE_WAIT) - return (-1); - - rv = ofp_send_featuresrequest(sc, con); - break; - - case OFP_STATE_FEATURE_WAIT: - if (state != OFP_STATE_ESTABLISHED) - return (-1); - break; - - case OFP_STATE_ESTABLISHED: - if (state != OFP_STATE_CLOSED) - return (-1); - break; - - default: - return (-1); - } - - /* Set the next state. */ - con->con_state = state; - - return (rv); -} diff --git a/usr.sbin/switchctl/parser.c b/usr.sbin/switchctl/parser.c deleted file mode 100644 index 01657a938ca..00000000000 --- a/usr.sbin/switchctl/parser.c +++ /dev/null @@ -1,541 +0,0 @@ -/* $OpenBSD: parser.c,v 1.10 2018/10/21 21:10:24 akoshibe Exp $ */ - -/* - * Copyright (c) 2010-2013 Reyk Floeter - * Copyright (c) 2004 Esben Norby - * Copyright (c) 2003, 2004 Henning Brauer - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" -#include "ofp_map.h" -#include "parser.h" - -enum token_type { - NOTOKEN, - ENDTOKEN, - KEYWORD, - PATH, - ADDRESS, - URI, - TABLE, - FLOWADD, - FLOWDELETE, - FLOWMODIFY, - FLOWAPPLY, - FLOWWRITE, - FLOWMATCH, - MATCHINPORT, - ACTIONOUTPUT, -}; - -struct token { - enum token_type type; - const char *keyword; - int value; - const struct token *next; -}; - -static const struct token t_main[]; -static const struct token t_reset[]; -static const struct token t_log[]; -static const struct token t_load[]; -static const struct token t_show[]; -static const struct token t_switch[]; -#if 0 -static const struct token t_switchreq[]; -#endif -static const struct token t_table[]; -static const struct token t_dump[]; -static const struct token t_flow[]; -static const struct token t_flowmod[]; -static const struct token t_flowmatch[]; -static const struct token t_matchinport[]; -static const struct token t_flowaction[]; -static const struct token t_actionoutput[]; -static const struct token t_connect[]; -static const struct token t_disconnect[]; -static const struct token t_forward_to[]; -static const struct token t_uri[]; - -static const struct token t_main[] = { - { KEYWORD, "connect", CONNECT, t_connect }, - { KEYWORD, "disconnect", DISCONNECT, t_disconnect }, - { KEYWORD, "dump", NONE, t_dump }, - { KEYWORD, "flow", NONE, t_flow }, - { KEYWORD, "load", LOAD, t_load }, - { KEYWORD, "log", NONE, t_log }, - { KEYWORD, "monitor", MONITOR, NULL }, - { KEYWORD, "reload", RELOAD, NULL }, - { KEYWORD, "reset", NONE, t_reset }, - { KEYWORD, "show", NONE, t_show }, - { KEYWORD, "switch", NONE, t_switch }, - { KEYWORD, "table", NONE, t_table }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_log[] = { - { KEYWORD, "verbose", LOG_VERBOSE, NULL }, - { KEYWORD, "brief", LOG_BRIEF, NULL }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_reset[] = { - { KEYWORD, "all", RESETALL, NULL }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_load[] = { - { PATH, "", NONE, NULL }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_table[] = { - { TABLE, "", NONE, t_main }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_switch[] = { - { URI, "", NONE, t_main }, - { ENDTOKEN, "", NONE, NULL } -}; - -#if 0 -static const struct token t_switchreq[] = { - { KEYWORD, "dump", NONE, t_dump }, - { KEYWORD, "flow", NONE, t_flow }, - { ENDTOKEN, "", NONE, NULL } -}; -#endif - -static const struct token t_dump[] = { - { KEYWORD, "desc", DUMP_DESC, NULL }, - { KEYWORD, "features", DUMP_FEATURES, NULL }, - { KEYWORD, "flows", DUMP_FLOWS, NULL }, - { KEYWORD, "tables", DUMP_TABLES, NULL }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_flow[] = { - { FLOWADD, "add", FLOW_ADD, t_flowmod }, - { FLOWDELETE, "delete", FLOW_DELETE, t_flowmod }, - { FLOWMODIFY, "modify", FLOW_MODIFY, t_flowmod }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_flowmod[] = { - { NOTOKEN, "", NONE, NULL }, - { FLOWAPPLY, "apply", NONE, t_flowaction }, - { FLOWWRITE, "write", NONE, t_flowaction }, - { FLOWMATCH, "match", NONE, t_flowmatch }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_flowmatch[] = { - { NOTOKEN, "", NONE, t_flowmod }, - { KEYWORD, "inport", NONE, t_matchinport }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_matchinport[] = { - { MATCHINPORT, "", NONE, t_flowmatch }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_flowaction[] = { - { NOTOKEN, "", NONE, t_flowmod }, - { KEYWORD, "output", NONE, t_actionoutput }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_actionoutput[] = { - { ACTIONOUTPUT, "", NONE, t_flowaction }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_show[] = { - { KEYWORD, "summary", SHOW_SUM, NULL }, - { KEYWORD, "switches", SHOW_SWITCHES, NULL }, - { KEYWORD, "macs", SHOW_MACS, NULL }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_connect[] = { - { ADDRESS, "", NONE, t_forward_to }, - { ENDTOKEN, "", NONE, NULL } -}; -static const struct token t_disconnect[] = { - { ADDRESS, "", NONE, NULL }, - { ENDTOKEN, "", NONE, NULL } -}; -static const struct token t_forward_to[] = { - { NOTOKEN, "", NONE, NULL }, - { KEYWORD, "forward-to", NONE, t_uri }, - { ENDTOKEN, "", NONE, NULL } -}; - -static const struct token t_uri[] = { - { URI, "", NONE, NULL }, - { ENDTOKEN, "", NONE, NULL } -}; - -static struct parse_result res; - -const struct token *match_token(char *, const struct token [], int); -void show_valid_args(const struct token [], int); -int parse_addr(const char *, - struct sockaddr_storage *); - -struct parse_result * -parse(int argc, char *argv[]) -{ - const struct token *table = t_main; - const struct token *match; - - bzero(&res, sizeof(res)); - - res.table = OFP_TABLE_ID_ALL; - - while (argc >= 0) { - if ((match = match_token(argv[0], table, 0)) == NULL) { - fprintf(stderr, "valid commands/args:\n"); - show_valid_args(table, 0); - return (NULL); - } - - argc--; - argv++; - - if (match->type == NOTOKEN || match->next == NULL) - break; - - table = match->next; - } - - if (argc > 0) { - fprintf(stderr, "superfluous argument: %s\n", argv[0]); - return (NULL); - } - - return (&res); -} - -int -parse_addr(const char *word, struct sockaddr_storage *ss) -{ - struct addrinfo hints, *ai; - struct sockaddr_un *un; - - memset(ss, 0, sizeof(*ss)); - - /* device */ - if (*word == '/') { - un = (struct sockaddr_un *)ss; - if (strlcpy(un->sun_path, word, sizeof(un->sun_path)) >= - sizeof(un->sun_path)) { - warnx("invalid path"); - return (-1); - } - un->sun_family = AF_LOCAL; - un->sun_len = sizeof(*un); - return (0); - } - - /* address */ - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; /* dummy */ - hints.ai_family = PF_UNSPEC; - hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(word, "0", &hints, &ai) == 0) { - memcpy(ss, ai->ai_addr, ai->ai_addrlen); - ss->ss_len = ai->ai_addrlen; - freeaddrinfo(ai); - return (0); - } - - /* FQDN */ - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; /* dummy */ - hints.ai_family = PF_UNSPEC; - hints.ai_flags = AI_ADDRCONFIG; - if (getaddrinfo(word, "0", &hints, &ai) == 0) { - /* Pick first name only */ - memcpy(ss, ai->ai_addr, ai->ai_addrlen); - ss->ss_len = ai->ai_addrlen; - freeaddrinfo(ai); - return (0); - } - - return (-1); -} - - -const struct token * -match_token(char *word, const struct token table[], int level) -{ - unsigned int i, j, match = 0; - int64_t val; - struct constmap *cm; - const char *errstr = NULL; - const struct token *t = NULL; - size_t len; - - for (i = 0; table[i].type != ENDTOKEN; i++) { - switch (table[i].type) { - case NOTOKEN: - if (word == NULL || strlen(word) == 0) { - match++; - t = &table[i]; - } - break; - case KEYWORD: - case FLOWADD: - case FLOWDELETE: - case FLOWMODIFY: - case FLOWMATCH: - case FLOWAPPLY: - case FLOWWRITE: - if (word != NULL && strncmp(word, table[i].keyword, - strlen(word)) == 0) { - match++; - t = &table[i]; - if (t->value) - res.action = t->value; - switch (table[i].type) { - case FLOWADD: - case FLOWDELETE: - case FLOWMODIFY: - if ((res.fbuf = - oflowmod_open(&res.fctx, - NULL, NULL, 0)) == NULL) - goto flowerr; - - /* Update header */ - if (table[i].type == FLOWDELETE) - res.fctx.ctx_fm->fm_command = - OFP_FLOWCMD_DELETE; - else if (table[i].type == FLOWMODIFY) - res.fctx.ctx_fm->fm_command = - OFP_FLOWCMD_MODIFY; - break; - case FLOWAPPLY: - val = OFP_INSTRUCTION_T_APPLY_ACTIONS; - if (oflowmod_instruction(&res.fctx, - val) == -1) - goto flowerr; - break; - case FLOWWRITE: - val = OFP_INSTRUCTION_T_WRITE_ACTIONS; - if (oflowmod_instruction(&res.fctx, - val) == -1) - goto flowerr; - break; - case FLOWMATCH: - if (oflowmod_mopen(&res.fctx) == -1) - goto flowerr; - break; - default: - break; - } - } - break; - case MATCHINPORT: - case ACTIONOUTPUT: - if (!match && word != NULL && strlen(word) > 0) { - match++; - t = &table[i]; - - val = -1; - - /* Is the port a keyword? */ - cm = ofp_port_map; - for (j = 0; cm[j].cm_name != NULL; j++) { - if (strcasecmp(cm[j].cm_name, - word) == 0) { - val = cm[j].cm_type; - break; - } - } - - /* Is the port a number? */ - if (val == -1) { - val = strtonum(word, 1, - UINT32_MAX, &errstr); - if (errstr != NULL) - val = -1; - } - - if (val == -1) { - fprintf(stderr, - "could not parse port:" - " %s\n", word); - return (NULL); - } - - switch (table[i].type) { - case MATCHINPORT: - if (oxm_inport(res.fbuf, val) == -1) - goto flowerr; - break; - case ACTIONOUTPUT: - if (action_output(res.fbuf, val, - OFP_CONTROLLER_MAXLEN_MAX) == -1) - goto flowerr; - break; - default: - break; - } - } - break; - case PATH: - if (!match && word != NULL && strlen(word) > 0) { - res.path = strdup(word); - match++; - t = &table[i]; - } - break; - case ADDRESS: - if (!match && word != NULL && strlen(word) > 0) { - parse_addr(word, &res.addr); - match++; - t = &table[i]; - } - break; - case TABLE: - if (word == NULL) - break; - res.table = strtonum(word, 0, - OFP_TABLE_ID_MAX, &errstr); - if (errstr) - res.table = OFP_TABLE_ID_ALL; - t = &table[i]; - match++; - break; - case URI: - if (!match && word != NULL && strlen(word) > 0) { - len = 4; - if (strncmp(word, "tcp:", len) == 0) - res.uri.swa_type = SWITCH_CONN_TCP; - else if (strncmp(word, "tls:", len) == 0) - res.uri.swa_type = SWITCH_CONN_TLS; - else if (strncmp(word, "/dev", len) == 0) { - res.uri.swa_type = SWITCH_CONN_LOCAL; - parse_addr(word, &res.uri.swa_addr); - match++; - t = &table[i]; - break; - } else { - /* set the default */ - res.uri.swa_type = SWITCH_CONN_TCP; - len = 0; - } - if (parsehostport(word + len, - (struct sockaddr *)&res.uri.swa_addr, - sizeof(res.uri.swa_addr)) != 0) { - fprintf(stderr, - "could not parse address: %s\n", - word); - return (NULL); - } - match++; - t = &table[i]; - } - break; - case ENDTOKEN: - break; - } - } - - if (match != 1) { - if (word == NULL) - fprintf(stderr, "missing argument:\n"); - else if (match > 1) - fprintf(stderr, "ambiguous argument: %s\n", word); - else if (match < 1) { - if (level == 0 && - table[0].type == NOTOKEN && table[0].next) - return (match_token(word, table[0].next, 1)); - else - fprintf(stderr, "unknown argument: %s\n", word); - } - return (NULL); - } - - return (t); - - flowerr: - (void)oflowmod_err(&res.fctx, __func__, __LINE__); - fprintf(stderr, "flow invalid\n"); - return (NULL); -} - -void -show_valid_args(const struct token table[], int level) -{ - int i; - - for (i = 0; table[i].type != ENDTOKEN; i++) { - switch (table[i].type) { - case NOTOKEN: - if (level == 0) - fprintf(stderr, " \n"); - break; - case KEYWORD: - case FLOWADD: - case FLOWDELETE: - case FLOWMODIFY: - case FLOWMATCH: - case FLOWAPPLY: - case FLOWWRITE: - fprintf(stderr, " %s\n", table[i].keyword); - break; - case MATCHINPORT: - case ACTIONOUTPUT: - fprintf(stderr, " \n"); - break; - case PATH: - fprintf(stderr, " \n"); - break; - case ADDRESS: - fprintf(stderr, "
\n"); - break; - case TABLE: - fprintf(stderr, " \n"); - break; - case URI: - fprintf(stderr, " \n"); - break; - case ENDTOKEN: - break; - } - } - - if (level == 0 && table[0].type == NOTOKEN && table[0].next) - return (show_valid_args(table[0].next, 1)); -} diff --git a/usr.sbin/switchctl/parser.h b/usr.sbin/switchctl/parser.h deleted file mode 100644 index 83fb4896ba9..00000000000 --- a/usr.sbin/switchctl/parser.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $OpenBSD: parser.h,v 1.4 2016/11/24 09:23:11 reyk Exp $ */ - -/* - * Copyright (c) 2007-2015 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _SWITCHCTL_PARSER_H -#define _SWITCHCTL_PARSER_H - -enum actions { - NONE, - FLOW_ADD, - FLOW_DELETE, - FLOW_MODIFY, - DUMP_DESC, - DUMP_FEATURES, - DUMP_FLOWS, - DUMP_TABLES, - SHOW_SUM, - SHOW_SWITCHES, - SHOW_MACS, - LOAD, - RELOAD, - MONITOR, - LOG_VERBOSE, - LOG_BRIEF, - RESETALL, - CONNECT, - DISCONNECT -}; - -struct parse_result { - enum actions action; - struct imsgbuf *ibuf; - char *path; - struct switch_address uri; - struct sockaddr_storage addr; - struct oflowmod_ctx fctx; - struct ibuf *fbuf; - int table; - int quiet; - int verbose; -}; - -#define HOST_IPADDR 1 -#define HOST_FQDN 2 - -struct parse_result *parse(int, char *[]); -void ofpclient(struct parse_result *, struct passwd *); - -#endif /* _SWITCHCTL_PARSER_H */ diff --git a/usr.sbin/switchctl/switchctl.8 b/usr.sbin/switchctl/switchctl.8 deleted file mode 100644 index 9874e7a6fde..00000000000 --- a/usr.sbin/switchctl/switchctl.8 +++ /dev/null @@ -1,136 +0,0 @@ -.\" $OpenBSD: switchctl.8,v 1.6 2018/10/21 21:10:24 akoshibe Exp $ -.\" -.\" Copyright (c) 2007-2015 Reyk Floeter -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: October 21 2018 $ -.Dt SWITCHCTL 8 -.Os -.Sh NAME -.Nm switchctl -.Nd control the SDN flow controller -.Sh SYNOPSIS -.Nm -.Op Fl q -.Op Fl s Ar socket -.Ar command -.Op Ar arg ... -.Sh DESCRIPTION -The -.Nm -program controls the -.Xr switchd 8 -daemon. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl q -Don't ask for confirmation of any default options. -.It Fl s Ar socket -Use -.Ar socket -instead of the default -.Pa /var/run/switchd.sock -to communicate with -.Xr switchd 8 . -.El -.Pp -The following commands are available to control -.Xr switchd 8 : -.Bl -tag -width Ds -.It Cm connect Ar address Op Cm forward-to Ar address -Connect to a new switch by -.Ar address , -for example -.Ar 10.1.1.1 , -or a -.Xr switch 4 -control device, for example -.Pa /dev/switch0 . -.Nm switchd -will forward all OpenFlow requests of the switch to a remote controller -if the optional -.Cm forward-to -.Ar address -is specified. -.It Cm disconnect Ar address -Close the client connection to a remote switch or a -.Xr switch 4 -control device. -.It Cm dump Ar address request -Request information from a remote switch or a -.Xr switch 4 -control device. -.Nm -will send an OpenFlow request to the remote switch that is specified by -.Ar address . -The -.Ar request -can be one of the following: -.Pp -.Bl -tag -width features -offset indent -compact -.It Cm desc -Request the switch description. -.It Cm features -Request the switch features. -.It Cm flows -Request the tables and flows. -.It Cm tables -Request the tables. -.El -.It Cm load Ar filename address -Reload the configuration from the specified file. -.It Cm log brief -Disable verbose logging. -.It Cm log verbose -Enable verbose logging. -.It Cm monitor -Monitor internal messages of the -.Xr switchd 8 -subsystems. -.It Cm reload -Reload the configuration from the default configuration file. -.It Cm reset all -Reset the running state. -.It Cm show macs -Display all known mac addresses. -.It Cm show summary -Display a list of all switches and mac addresses. -.It Cm show switches -Display all known switches. -.El -.Sh FILES -.Bl -tag -width "/var/run/switchd.sockXX" -compact -.It /etc/switchd.conf -Active configuration. -.It /var/run/switchd.sock -default -.Ux Ns -domain -socket used for communication with -.Xr switchd 8 -.El -.Sh SEE ALSO -.Xr bridge 4 , -.Xr switchd.conf 5 , -.Xr switchd 8 -.Sh HISTORY -The -.Nm -program first appeared in -.Ox 6.1 . -.Sh AUTHORS -The -.Nm -program was written by -.An Reyk Floeter Aq Mt reyk@openbsd.org . diff --git a/usr.sbin/switchctl/switchctl.c b/usr.sbin/switchctl/switchctl.c deleted file mode 100644 index d1017786286..00000000000 --- a/usr.sbin/switchctl/switchctl.c +++ /dev/null @@ -1,372 +0,0 @@ -/* $OpenBSD: switchctl.c,v 1.9 2018/10/24 18:06:21 akoshibe Exp $ */ - -/* - * Copyright (c) 2007-2015 Reyk Floeter - * Copyright (c) 2005 Claudio Jeker - * Copyright (c) 2004, 2005 Esben Norby - * Copyright (c) 2003 Henning Brauer - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" -#include "parser.h" - -__dead void usage(void); - -struct imsgname { - int type; - char *name; - void (*func)(struct imsg *); -}; - -int show_summary_msg(struct imsg *, int); - -struct imsgname *monitor_lookup(uint8_t); -void monitor_id(struct imsg *); -int monitor(struct imsg *); - -int ca_opt(struct parse_result *); - -struct imsgname imsgs[] = { - { IMSG_CTL_OK, "ok", NULL }, - { IMSG_CTL_FAIL, "fail", NULL }, - { IMSG_CTL_VERBOSE, "verbose", NULL }, - { IMSG_CTL_RELOAD, "reload", NULL }, - { IMSG_CTL_RESET, "reset", NULL }, - { 0, NULL, NULL } - -}; -struct imsgname imsgunknown = { - -1, "", NULL -}; - -struct imsgbuf *ibuf; - -__dead void -usage(void) -{ - extern char *__progname; - - fprintf(stderr, "usage: %s [-q] [-s socket] command [arg ...]\n", - __progname); - exit(1); -} - -int -main(int argc, char *argv[]) -{ - struct sockaddr_un sun; - struct parse_result *res; - struct imsg imsg; - struct switch_client swc; - struct switch_address *to; - struct passwd *pw; - int ctl_sock; - int done = 1; - int n; - int ch; - int v = 0; - int quiet = 0; - int verbose = 0; - const char *sock = SWITCHD_SOCKET; - - while ((ch = getopt(argc, argv, "qs:v")) != -1) { - switch (ch) { - case 'q': - quiet = 1; - break; - case 's': - sock = optarg; - break; - case 'v': - verbose = 2; - break; - default: - usage(); - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if ((pw = getpwnam(SWITCHD_USER)) == NULL) - fatal("switchctl: getpwnam"); - - /* - * pledge in switchctl: - * stdio - for malloc and basic I/O including events. - * rpath - for reading from the /dev/switch device. - * wpath - for accessing the /dev/switch device. - * inet - for handling tcp connections with OpenFlow peers. - * unix - for opening the control socket. - * dns - for parsehostport() in the device spec. - */ - if (pledge("stdio rpath wpath inet unix dns", NULL) == -1) - err(1, "pledge"); - - log_init(quiet ? 0 : 2, LOG_USER); - - /* parse options */ - if ((res = parse(argc, argv)) == NULL) - exit(1); - - res->quiet = quiet; - res->verbose = verbose; - - if (res->quiet && res->verbose) - fatal("conflicting -v and -q options"); - - switch (res->action) { - case NONE: - usage(); - break; - case DUMP_DESC: - case DUMP_FEATURES: - case DUMP_FLOWS: - case DUMP_TABLES: - case FLOW_ADD: - case FLOW_DELETE: - case FLOW_MODIFY: - ofpclient(res, pw); - break; - default: - goto connect; - } - - return (0); - - connect: - /* connect to sdnflowd control socket */ - if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - err(1, "socket"); - - bzero(&sun, sizeof(sun)); - sun.sun_family = AF_UNIX; - strlcpy(sun.sun_path, sock, sizeof(sun.sun_path)); - reconnect: - if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { - /* Keep retrying if running in monitor mode */ - if (res->action == MONITOR && - (errno == ENOENT || errno == ECONNREFUSED)) { - usleep(100); - goto reconnect; - } - err(1, "connect: %s", sock); - } - - if (pledge("stdio", NULL) == -1) - err(1, "pledge"); - - if (res->ibuf != NULL) - ibuf = res->ibuf; - else - if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) - err(1, "malloc"); - imsg_init(ibuf, ctl_sock); - - /* process user request */ - switch (res->action) { - case RESETALL: - v = RESET_ALL; - break; - case LOG_VERBOSE: - v = 2; - break; - case LOG_BRIEF: - default: - v = 0; - break; - } - - switch (res->action) { - case NONE: - usage(); - /* NOTREACHED */ - break; - case SHOW_SUM: - case SHOW_SWITCHES: - case SHOW_MACS: - imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0); - printf("%-4s\t%-4s\t%-8s\t%-24s\t%s\n", - "Switch", "Port", "Type", "Name", "Info"); - done = 0; - break; - case CONNECT: - case DISCONNECT: - memset(&swc, 0, sizeof(swc)); - if (res->addr.ss_family == AF_UNSPEC) - errx(1, "invalid address"); - - memcpy(&swc.swc_addr.swa_addr, &res->addr, sizeof(res->addr)); - if (res->action == DISCONNECT) { - imsg_compose(ibuf, IMSG_CTL_DISCONNECT, 0, 0, -1, - &swc, sizeof(swc)); - break; - } - - to = &swc.swc_target; - memcpy(to, &res->uri, sizeof(*to)); - - imsg_compose(ibuf, IMSG_CTL_CONNECT, 0, 0, -1, - &swc, sizeof(swc)); - break; - case RESETALL: - imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &v, sizeof(v)); - printf("reset request sent.\n"); - break; - case LOAD: - imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, - res->path, strlen(res->path)); - break; - case RELOAD: - imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); - break; - case MONITOR: - imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0); - done = 0; - break; - case LOG_VERBOSE: - case LOG_BRIEF: - imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &v, sizeof(v)); - printf("logging request sent.\n"); - break; - default: - break; - } - - while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) - err(1, "write error"); - - while (!done) { - if ((n = imsg_read(ibuf)) == -1) - errx(1, "imsg_read error"); - if (n == 0) - errx(1, "pipe closed"); - - while (!done) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - errx(1, "imsg_get error"); - if (n == 0) - break; - switch (res->action) { - case SHOW_SUM: - case SHOW_SWITCHES: - case SHOW_MACS: - done = show_summary_msg(&imsg, res->action); - break; - case MONITOR: - done = monitor(&imsg); - break; - default: - break; - } - imsg_free(&imsg); - } - } - close(ctl_sock); - free(ibuf); - - return (0); -} - -int -show_summary_msg(struct imsg *imsg, int type) -{ - struct switch_control *sw; - struct macaddr *mac; - struct timeval tv; - static unsigned int sw_id = 0; - - switch (imsg->hdr.type) { - case IMSG_CTL_SWITCH: - IMSG_SIZE_CHECK(imsg, sw); - sw = imsg->data; - sw_id = sw->sw_id; - - if (!(type == SHOW_SUM || type == SHOW_SWITCHES)) - break; - printf("%-4u\t%-4s\t%-8s\t%-24s\n", - sw->sw_id, "", "switch", - print_host(&sw->sw_addr, NULL, 0)); - break; - case IMSG_CTL_MAC: - IMSG_SIZE_CHECK(imsg, mac); - mac = imsg->data; - - if (!(type == SHOW_SUM || type == SHOW_MACS)) - break; - - getmonotime(&tv); - printf("%-4u\t%-4u\t%-8s\t%-24s\tage %llds\n", - sw_id, mac->mac_port, "mac", - print_ether(mac->mac_addr), - (long long)tv.tv_sec - mac->mac_age); - break; - case IMSG_CTL_END: - return (1); - default: - errx(1, "wrong message in summary: %u", imsg->hdr.type); - break; - } - return (0); -} - -struct imsgname * -monitor_lookup(uint8_t type) -{ - int i; - - for (i = 0; imsgs[i].name != NULL; i++) - if (imsgs[i].type == type) - return (&imsgs[i]); - return (&imsgunknown); -} - -int -monitor(struct imsg *imsg) -{ - time_t now; - int done = 0; - struct imsgname *imn; - - now = time(NULL); - - imn = monitor_lookup(imsg->hdr.type); - printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name, - imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid); - printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now)); - if (imn->type == -1) - done = 1; - if (imn->func != NULL) - (*imn->func)(imsg); - - return (done); -} diff --git a/usr.sbin/switchd/Makefile b/usr.sbin/switchd/Makefile deleted file mode 100644 index 7312b739785..00000000000 --- a/usr.sbin/switchd/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# $OpenBSD: Makefile,v 1.8 2017/07/06 12:15:23 espie Exp $ - -PROG= switchd -MAN= switchd.8 switchd.conf.5 - -SRCS= imsg_util.c log.c packet.c proc.c switch.c timer.c util.c -SRCS+= switchd.c control.c ofp.c ofp10.c ofp13.c ofp_common.c ofrelay.c -SRCS+= ${.OBJDIR}/ofp_map.c ${.OBJDIR}/ofp10_map.c -SRCS+= parse.y ofcconn.c - -LDADD= -levent -lutil -DPADD= ${LIBEVENT} ${LIBUTIL} - -CFLAGS+= -Wall -I${.CURDIR} -I${.CURDIR}/../switchd -CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes -CFLAGS+= -Wmissing-declarations -CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual -CFLAGS+= -Wsign-compare - -GENERATED= ofp_map.c ofp10_map.c -CLEANFILES+= ${GENERATED} -YFLAGS= - -ofp_map.c: genmap.sh ${.CURDIR}/ofp_map.h ${.CURDIR}/../../sys/net/ofp.h - /bin/sh ${.CURDIR}/genmap.sh -i ${.CURDIR}/../../sys/net/ofp.h -t ofp \ - -m ${.CURDIR}/ofp_map.h -h '' > $@ - @touch $@ - -ofp10_map.c: genmap.sh ${.CURDIR}/ofp_map.h ${.CURDIR}/ofp10.h - /bin/sh ${.CURDIR}/genmap.sh -i ${.CURDIR}/ofp10.h -t ofp10 \ - -m ${.CURDIR}/ofp_map.h -h '"ofp10.h"' > $@ - @touch $@ - -.include diff --git a/usr.sbin/switchd/control.c b/usr.sbin/switchd/control.c deleted file mode 100644 index 50ceb10b459..00000000000 --- a/usr.sbin/switchd/control.c +++ /dev/null @@ -1,379 +0,0 @@ -/* $OpenBSD: control.c,v 1.10 2021/04/20 21:11:56 dv Exp $ */ - -/* - * Copyright (c) 2010-2016 Reyk Floeter - * Copyright (c) 2003, 2004 Henning Brauer - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "proc.h" -#include "switchd.h" - -#define CONTROL_BACKLOG 5 - -struct ctl_connlist ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); - -void - control_accept(int, short, void *); -struct ctl_conn - *control_connbyfd(int); -void control_close(int, struct control_sock *); -void control_dispatch_imsg(int, short, void *); -void control_imsg_forward(struct imsg *); -void control_run(struct privsep *, struct privsep_proc *, void *); - -int control_dispatch_ofp(int, struct privsep_proc *, struct imsg *); - -static struct privsep_proc procs[] = { - { "ofp", PROC_OFP, control_dispatch_ofp }, - { "parent", PROC_PARENT, NULL }, - { "ofcconn", PROC_OFCCONN, NULL } -}; - -void -control(struct privsep *ps, struct privsep_proc *p) -{ - proc_run(ps, p, procs, nitems(procs), control_run, NULL); -} - -void -control_run(struct privsep *ps, struct privsep_proc *p, void *arg) -{ - /* - * pledge in the control process: - * stdio - for malloc and basic I/O including events. - * unix - for the control socket. - * recvfd - for the proc fd exchange. - */ - if (pledge("stdio unix recvfd", NULL) == -1) - fatal("pledge"); -} - -int -control_dispatch_ofp(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - int cfd; - struct ctl_conn *c; - uint8_t *d = imsg->data; - size_t s; - - switch (imsg->hdr.type) { - case IMSG_CTL_SWITCH: - case IMSG_CTL_MAC: - IMSG_SIZE_CHECK(imsg, &cfd); - memcpy(&cfd, d, sizeof(cfd)); - - if ((c = control_connbyfd(cfd)) == NULL) - fatalx("invalid control connection"); - - s = IMSG_DATA_SIZE(imsg) - sizeof(cfd); - d += sizeof(cfd); - imsg_compose_event(&c->iev, imsg->hdr.type, 0, 0, -1, d, s); - return (0); - case IMSG_CTL_END: - IMSG_SIZE_CHECK(imsg, &cfd); - memcpy(&cfd, d, sizeof(cfd)); - - if ((c = control_connbyfd(cfd)) == NULL) - fatalx("invalid control connection"); - - imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); - return (0); - - default: - break; - } - - return (-1); -} - -int -control_init(struct privsep *ps, struct control_sock *cs) -{ - struct switchd *env = ps->ps_env; - struct sockaddr_un sun; - int fd; - mode_t old_umask, mode; - - if (cs->cs_name == NULL) - return (0); - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - log_warn("%s: socket", __func__); - return (-1); - } - - sun.sun_family = AF_UNIX; - if (strlcpy(sun.sun_path, cs->cs_name, - sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { - log_warn("%s: %s name too long", __func__, cs->cs_name); - close(fd); - return (-1); - } - - if (unlink(cs->cs_name) == -1) - if (errno != ENOENT) { - log_warn("%s: unlink %s", __func__, cs->cs_name); - close(fd); - return (-1); - } - - if (cs->cs_restricted) { - old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH); - mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; - } else { - old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); - mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; - } - - if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { - log_warn("%s: bind: %s", __func__, cs->cs_name); - close(fd); - (void)umask(old_umask); - return (-1); - } - (void)umask(old_umask); - - if (chmod(cs->cs_name, mode) == -1) { - log_warn("%s: chmod", __func__); - close(fd); - (void)unlink(cs->cs_name); - return (-1); - } - - socket_set_blockmode(fd, BM_NONBLOCK); - cs->cs_fd = fd; - cs->cs_env = env; - - return (0); -} - -int -control_listen(struct control_sock *cs) -{ - if (cs->cs_name == NULL) - return (0); - - if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) { - log_warn("%s: listen", __func__); - return (-1); - } - - event_set(&cs->cs_ev, cs->cs_fd, EV_READ, - control_accept, cs); - event_add(&cs->cs_ev, NULL); - evtimer_set(&cs->cs_evt, control_accept, cs); - - return (0); -} - -/* ARGSUSED */ -void -control_accept(int listenfd, short event, void *arg) -{ - struct control_sock *cs = arg; - int connfd; - socklen_t len; - struct sockaddr_un sun; - struct ctl_conn *c; - - event_add(&cs->cs_ev, NULL); - if ((event & EV_TIMEOUT)) - return; - - len = sizeof(sun); - if ((connfd = accept(listenfd, - (struct sockaddr *)&sun, &len)) == -1) { - /* - * Pause accept if we are out of file descriptors, or - * libevent will haunt us here too. - */ - if (errno == ENFILE || errno == EMFILE) { - struct timeval evtpause = { 1, 0 }; - - event_del(&cs->cs_ev); - evtimer_add(&cs->cs_evt, &evtpause); - } else if (errno != EWOULDBLOCK && errno != EINTR && - errno != ECONNABORTED) - log_warn("%s: accept", __func__); - return; - } - - socket_set_blockmode(connfd, BM_NONBLOCK); - - if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { - log_warn("%s", __func__); - close(connfd); - return; - } - - imsg_init(&c->iev.ibuf, connfd); - c->iev.handler = control_dispatch_imsg; - c->iev.events = EV_READ; - c->iev.data = cs; - event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, - c->iev.handler, c->iev.data); - event_add(&c->iev.ev, NULL); - - TAILQ_INSERT_TAIL(&ctl_conns, c, entry); -} - -struct ctl_conn * -control_connbyfd(int fd) -{ - struct ctl_conn *c; - - TAILQ_FOREACH(c, &ctl_conns, entry) { - if (c->iev.ibuf.fd == fd) - break; - } - - return (c); -} - -void -control_close(int fd, struct control_sock *cs) -{ - struct ctl_conn *c; - - if ((c = control_connbyfd(fd)) == NULL) { - log_warn("%s: fd %d: not found", __func__, fd); - return; - } - - msgbuf_clear(&c->iev.ibuf.w); - TAILQ_REMOVE(&ctl_conns, c, entry); - - event_del(&c->iev.ev); - close(c->iev.ibuf.fd); - - /* Some file descriptors are available again. */ - if (evtimer_pending(&cs->cs_evt, NULL)) { - evtimer_del(&cs->cs_evt); - event_add(&cs->cs_ev, NULL); - } - - free(c); -} - -/* ARGSUSED */ -void -control_dispatch_imsg(int fd, short event, void *arg) -{ - struct control_sock *cs = arg; - struct switchd *env = cs->cs_env; - struct ctl_conn *c; - struct imsg imsg; - int n, v; - - if ((c = control_connbyfd(fd)) == NULL) { - log_warn("%s: fd %d: not found", __func__, fd); - return; - } - - if (event & EV_READ) { - if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || - n == 0) { - control_close(fd, cs); - return; - } - } - if (event & EV_WRITE) { - if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { - control_close(fd, cs); - return; - } - } - - for (;;) { - if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { - control_close(fd, cs); - return; - } - - if (n == 0) - break; - - control_imsg_forward(&imsg); - - switch (imsg.hdr.type) { - case IMSG_CTL_SHOW_SUM: - /* Forward request and use control fd as _id_ */ - proc_compose(&env->sc_ps, PROC_OFP, - imsg.hdr.type, &fd, sizeof(fd)); - break; - case IMSG_CTL_CONNECT: - case IMSG_CTL_DISCONNECT: - proc_compose(&env->sc_ps, PROC_PARENT, - imsg.hdr.type, imsg.data, IMSG_DATA_SIZE(&imsg)); - break; - case IMSG_CTL_NOTIFY: - if (c->flags & CTL_CONN_NOTIFY) { - log_debug("%s: " - "client requested notify more than once", - __func__); - imsg_compose_event(&c->iev, IMSG_CTL_FAIL, - 0, 0, -1, NULL, 0); - break; - } - c->flags |= CTL_CONN_NOTIFY; - break; - case IMSG_CTL_VERBOSE: - IMSG_SIZE_CHECK(&imsg, &v); - - memcpy(&v, imsg.data, sizeof(v)); - log_setverbose(v); - - proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); - proc_forward_imsg(&env->sc_ps, &imsg, PROC_OFP, -1); - break; - default: - log_debug("%s: error handling imsg %d", - __func__, imsg.hdr.type); - break; - } - imsg_free(&imsg); - } - - imsg_event_add(&c->iev); -} - -void -control_imsg_forward(struct imsg *imsg) -{ - struct ctl_conn *c; - - TAILQ_FOREACH(c, &ctl_conns, entry) - if (c->flags & CTL_CONN_NOTIFY) - imsg_compose(&c->iev.ibuf, imsg->hdr.type, - 0, imsg->hdr.pid, -1, imsg->data, - imsg->hdr.len - IMSG_HEADER_SIZE); -} diff --git a/usr.sbin/switchd/genmap.sh b/usr.sbin/switchd/genmap.sh deleted file mode 100644 index 2c61975809e..00000000000 --- a/usr.sbin/switchd/genmap.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/sh -# $OpenBSD: genmap.sh,v 1.6 2016/11/18 16:49:35 reyk Exp $ - -# Copyright (c) 2010-2013 Reyk Floeter -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -TOKEN="" -MAPFILE="" -INPUT="" -HEADER="" -DESCR=0 - -args=`getopt di:o:h:t:m: $*` - -if [ $? -ne 0 ]; then - echo "usage: $0 [-d] -i input -h header -t token [-m mapfile]" - exit 1 -fi - -set -- $args -while [ $# -ne 0 ]; do - case "$1" in - -d) - DESCR=1; shift; - ;; - -i) - INPUT="$2"; shift; shift; - ;; - -h) - HEADER="$2"; shift; shift; - ;; - -t) - TOKEN="$2"; shift; shift; - ;; - -m) - MAPFILE="$2"; shift; shift; - ;; - --) - shift; - break - ;; - esac -done - -if [ -z "$MAPFILE" ]; then - MAPFILE=$INPUT -fi - -TOK=$(echo ${TOKEN} | tr "[:lower:]" "[:upper:]") -tok=$(echo ${TOKEN} | tr "[:upper:]" "[:lower:]") -INC="#include ${HEADER}" -FILE=$(basename ${INPUT}) -MAP=$(grep "struct constmap ${tok}_" $MAPFILE | - sed -Ee "s/.*${tok}_(.+)_map.*/\1/g") - -# Print license/copyright notice and headers -cat < -${INC} -#include "ofp_map.h" - -EOF - -for i in $MAP; do - lower=$(echo $i | tr "[:upper:]" "[:lower:]") - upper=$(echo $i | tr "[:lower:]" "[:upper:]") - - echo "struct constmap ${tok}_${lower}_map[] = {" - - X="${TOK}_${upper}_" - - if [ $DESCR = 1 ]; then - # with the description field - grep "$X" $INPUT | grep -v '\\' | sed -Ee \ - "s/#define.*${X}([^[:blank:]]+).*\/\* (.+) \*\/$\ -/ { ${X}\1, \"\1\", \"\2\" },/" | grep -v '\#define' - else - # without the description field - grep "$X" $INPUT | grep -v '\\' | sed -Ee \ - "s/#define.*${X}([^[:blank:]]+).*\/\* .+ \*\/$\ -/ { ${X}\1, \"\1\" },/" | grep -v '\#define' - fi - - echo " { 0 }" - echo "};" -done diff --git a/usr.sbin/switchd/imsg_util.c b/usr.sbin/switchd/imsg_util.c deleted file mode 100644 index e7e79fdee1d..00000000000 --- a/usr.sbin/switchd/imsg_util.c +++ /dev/null @@ -1,236 +0,0 @@ -/* $OpenBSD: imsg_util.c,v 1.5 2016/09/30 11:57:57 reyk Exp $ */ - -/* - * Copyright (c) 2010-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" - -/* - * Extending the imsg buffer API for internal use - */ - -int -ibuf_cat(struct ibuf *dst, struct ibuf *src) -{ - return (ibuf_add(dst, src->buf, ibuf_size(src))); -} - -void -ibuf_zero(struct ibuf *buf) -{ - explicit_bzero(buf->buf, buf->wpos); -} - -void -ibuf_reset(struct ibuf *buf) -{ - ibuf_zero(buf); - buf->rpos = buf->wpos = 0; -} - -struct ibuf * -ibuf_new(void *data, size_t len) -{ - struct ibuf *buf; - - if ((buf = ibuf_dynamic(len, - SWITCHD_MSGBUF_MAX)) == NULL) - return (NULL); - - ibuf_zero(buf); - - if (data == NULL && len) { - if (ibuf_advance(buf, len) == NULL) { - ibuf_free(buf); - return (NULL); - } - } else { - if (ibuf_add(buf, data, len) != 0) { - ibuf_free(buf); - return (NULL); - } - } - - return (buf); -} - -struct ibuf * -ibuf_static(void) -{ - struct ibuf *buf; - - if ((buf = ibuf_open(SWITCHD_MSGBUF_MAX)) == NULL) - return (NULL); - - ibuf_zero(buf); - - return (buf); -} - -void * -ibuf_advance(struct ibuf *buf, size_t len) -{ - void *ptr; - - if ((ptr = ibuf_reserve(buf, len)) != NULL) - memset(ptr, 0, len); - - return (ptr); -} - -void -ibuf_release(struct ibuf *buf) -{ - if (buf == NULL) - return; - if (buf->buf != NULL) { - ibuf_zero(buf); - free(buf->buf); - } - free(buf); -} - -size_t -ibuf_length(struct ibuf *buf) -{ - if (buf == NULL || buf->buf == NULL) - return (0); - return (ibuf_size(buf)); -} - -uint8_t * -ibuf_data(struct ibuf *buf) -{ - return (ibuf_seek(buf, 0, 0)); -} - -void * -ibuf_getdata(struct ibuf *buf, size_t len) -{ - void *data; - - if ((data = ibuf_seek(buf, buf->rpos, len)) == NULL) - return (NULL); - buf->rpos += len; - - return (data); -} - -ssize_t -ibuf_dataleft(struct ibuf *buf) -{ - return (buf->wpos - buf->rpos); -} - -size_t -ibuf_dataoffset(struct ibuf *buf) -{ - return (buf->rpos); -} - -struct ibuf * -ibuf_get(struct ibuf *buf, size_t len) -{ - void *data; - - if ((data = ibuf_getdata(buf, len)) == NULL) - return (NULL); - - return (ibuf_new(data, len)); -} - -struct ibuf * -ibuf_dup(struct ibuf *buf) -{ - if (buf == NULL) - return (NULL); - return (ibuf_new(ibuf_data(buf), ibuf_size(buf))); -} - -struct ibuf * -ibuf_random(size_t len) -{ - struct ibuf *buf; - void *ptr; - - if ((buf = ibuf_open(len)) == NULL) - return (NULL); - if ((ptr = ibuf_reserve(buf, len)) == NULL) { - ibuf_free(buf); - return (NULL); - } - arc4random_buf(ptr, len); - return (buf); -} - -int -ibuf_setsize(struct ibuf *buf, size_t len) -{ - if (len > buf->size) - return (-1); - buf->wpos = len; - return (0); -} - -int -ibuf_setmax(struct ibuf *buf, size_t len) -{ - if (len > buf->size) - return (-1); - buf->max = len; - return (0); -} - -int -ibuf_prepend(struct ibuf *buf, void *data, size_t len) -{ - struct ibuf *new; - - /* Swap buffers (we could also use memmove here) */ - if ((new = ibuf_new(data, len)) == NULL) - return (-1); - if (ibuf_cat(new, buf) == -1) { - ibuf_release(new); - return (-1); - } - free(buf->buf); - memcpy(buf, new, sizeof(*buf)); - free(new); - - return (0); -} diff --git a/usr.sbin/switchd/log.c b/usr.sbin/switchd/log.c deleted file mode 100644 index 1d0c004194b..00000000000 --- a/usr.sbin/switchd/log.c +++ /dev/null @@ -1,218 +0,0 @@ -/* $OpenBSD: log.c,v 1.5 2017/03/21 12:06:56 bluhm Exp $ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include - -static int debug; -static int verbose; -const char *log_procname; - -void log_init(int, int); -void log_procinit(const char *); -void log_setverbose(int); -int log_getverbose(void); -void log_warn(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_warnx(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_info(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_debug(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void logit(int, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); -void vlog(int, const char *, va_list) - __attribute__((__format__ (printf, 2, 0))); -__dead void fatal(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -__dead void fatalx(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); - -void -log_init(int n_debug, int facility) -{ - extern char *__progname; - - debug = n_debug; - verbose = n_debug; - log_procinit(__progname); - - if (!debug) - openlog(__progname, LOG_PID | LOG_NDELAY, facility); - - tzset(); -} - -void -log_procinit(const char *procname) -{ - if (procname != NULL) - log_procname = procname; -} - -void -log_setverbose(int v) -{ - verbose = v; -} - -int -log_getverbose(void) -{ - return (verbose); -} - -void -logit(int pri, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vlog(pri, fmt, ap); - va_end(ap); -} - -void -vlog(int pri, const char *fmt, va_list ap) -{ - char *nfmt; - int saved_errno = errno; - - if (debug) { - /* best effort in out of mem situations */ - if (asprintf(&nfmt, "%s\n", fmt) == -1) { - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - } else { - vfprintf(stderr, nfmt, ap); - free(nfmt); - } - fflush(stderr); - } else - vsyslog(pri, fmt, ap); - - errno = saved_errno; -} - -void -log_warn(const char *emsg, ...) -{ - char *nfmt; - va_list ap; - int saved_errno = errno; - - /* best effort to even work in out of memory situations */ - if (emsg == NULL) - logit(LOG_ERR, "%s", strerror(saved_errno)); - else { - va_start(ap, emsg); - - if (asprintf(&nfmt, "%s: %s", emsg, - strerror(saved_errno)) == -1) { - /* we tried it... */ - vlog(LOG_ERR, emsg, ap); - logit(LOG_ERR, "%s", strerror(saved_errno)); - } else { - vlog(LOG_ERR, nfmt, ap); - free(nfmt); - } - va_end(ap); - } - - errno = saved_errno; -} - -void -log_warnx(const char *emsg, ...) -{ - va_list ap; - - va_start(ap, emsg); - vlog(LOG_ERR, emsg, ap); - va_end(ap); -} - -void -log_info(const char *emsg, ...) -{ - va_list ap; - - va_start(ap, emsg); - vlog(LOG_INFO, emsg, ap); - va_end(ap); -} - -void -log_debug(const char *emsg, ...) -{ - va_list ap; - - if (verbose > 1) { - va_start(ap, emsg); - vlog(LOG_DEBUG, emsg, ap); - va_end(ap); - } -} - -static void -vfatalc(int code, const char *emsg, va_list ap) -{ - static char s[BUFSIZ]; - const char *sep; - - if (emsg != NULL) { - (void)vsnprintf(s, sizeof(s), emsg, ap); - sep = ": "; - } else { - s[0] = '\0'; - sep = ""; - } - if (code) - logit(LOG_CRIT, "%s: %s%s%s", - log_procname, s, sep, strerror(code)); - else - logit(LOG_CRIT, "%s%s%s", log_procname, sep, s); -} - -void -fatal(const char *emsg, ...) -{ - va_list ap; - - va_start(ap, emsg); - vfatalc(errno, emsg, ap); - va_end(ap); - exit(1); -} - -void -fatalx(const char *emsg, ...) -{ - va_list ap; - - va_start(ap, emsg); - vfatalc(0, emsg, ap); - va_end(ap); - exit(1); -} diff --git a/usr.sbin/switchd/ofcconn.c b/usr.sbin/switchd/ofcconn.c deleted file mode 100644 index 1f2973a9ead..00000000000 --- a/usr.sbin/switchd/ofcconn.c +++ /dev/null @@ -1,641 +0,0 @@ -/* $OpenBSD: ofcconn.c,v 1.13 2019/06/28 13:32:51 deraadt Exp $ */ - -/* - * Copyright (c) 2016 YASUOKA Masahiko - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ofp10.h" -#include "types.h" -#include "switchd.h" - -int ofcconn_dispatch_parent(int, struct privsep_proc *, struct imsg *); - -static struct privsep_proc procs[] = { - { "parent", PROC_PARENT, ofcconn_dispatch_parent }, - { "control", PROC_CONTROL, NULL }, -}; - -struct ofcconn; - -/* OpenFlow Switch */ -struct ofsw { - int os_fd; - char *os_name; - int os_write_ready; - TAILQ_HEAD(,ofcconn) os_ofcconns; - struct event os_evio; - TAILQ_ENTRY(ofsw) os_next; -}; -TAILQ_HEAD(, ofsw) ofsw_list = TAILQ_HEAD_INITIALIZER(ofsw_list); - -/* OpenFlow Channel Connection */ -struct ofcconn { - struct ofsw *oc_sw; - char *oc_name; - struct sockaddr_storage oc_peer; - int oc_sock; - int oc_write_ready; - int oc_connected; - int oc_conn_fails; - struct ibuf *oc_buf; - TAILQ_ENTRY(ofcconn) oc_next; - struct event oc_evsock; - struct event oc_evtimer; -}; - -struct ofsw *ofsw_create(const char *, int); -void ofsw_close(struct ofsw *); -void ofsw_free(struct ofsw *); -void ofsw_on_io(int, short, void *); -int ofsw_write(struct ofsw *, struct ofcconn *); -int ofsw_ofc_write_ready(struct ofsw *); -void ofsw_reset_event_handlers(struct ofsw *); -int ofsw_new_ofcconn(struct ofsw *, struct switch_address *); -int ofcconn_connect(struct ofcconn *); -void ofcconn_on_sockio(int, short, void *); -void ofcconn_connect_again(struct ofcconn *); -void ofcconn_on_timer(int, short, void *); -void ofcconn_reset_event_handlers(struct ofcconn *); -void ofcconn_io_fail(struct ofcconn *); -void ofcconn_close(struct ofcconn *); -void ofcconn_free(struct ofcconn *); -void ofcconn_shutdown_all(void); -int ofcconn_send_hello(struct ofcconn *); -void ofcconn_run(struct privsep *, struct privsep_proc *, void *); - -void -ofcconn(struct privsep *ps, struct privsep_proc *p) -{ - p->p_shutdown = ofcconn_shutdown; - proc_run(ps, p, procs, nitems(procs), ofcconn_run, NULL); -} - -void -ofcconn_run(struct privsep *ps, struct privsep_proc *p, void *arg) -{ - /* - * pledge in the ofcconn process: - * stdio - for malloc and basic I/O including events. - * inet - for socket operations and OpenFlow connections. - * recvfd - for receiving new sockets on reload. - */ - if (pledge("stdio inet recvfd", NULL) == -1) - fatal("pledge"); -} - -void -ofcconn_shutdown(void) -{ - struct ofsw *e, *t; - - TAILQ_FOREACH_SAFE(e, &ofsw_list, os_next, t) { - ofsw_close(e); - ofsw_free(e); - } -} - -int -ofcconn_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - struct ofsw *os; - struct switch_client swc; - struct sockaddr_un *un; - - switch (imsg->hdr.type) { - case IMSG_CTL_CONNECT: - if (IMSG_DATA_SIZE(imsg) < sizeof(swc)) { - log_warnx("%s: IMSG_CTL_CONNECT: " - "invalid message size", __func__); - return (0); - } - memcpy(&swc, imsg->data, sizeof(swc)); - un = (struct sockaddr_un *)&swc.swc_addr.swa_addr; - - if ((os = ofsw_create(un->sun_path, imsg->fd)) != NULL) - ofsw_new_ofcconn(os, &swc.swc_target); - return (0); - case IMSG_CTL_DISCONNECT: - if (IMSG_DATA_SIZE(imsg) < sizeof(swc)) { - log_warnx("%s: IMSG_CTL_DEVICE_DISCONNECT: " - "invalid message size", __func__); - return (0); - } - memcpy(&swc, imsg->data, sizeof(swc)); - un = (struct sockaddr_un *)&swc.swc_addr.swa_addr; - - TAILQ_FOREACH(os, &ofsw_list, os_next) { - if (!strcmp(os->os_name, un->sun_path)) - break; - } - if (os) { - log_warnx("%s: closed by request", os->os_name); - ofsw_close(os); - ofsw_free(os); - } - return (0); - default: - break; - } - - return (-1); -} - -struct ofsw * -ofsw_create(const char *name, int fd) -{ - struct ofsw *os = NULL; - - if ((os = calloc(1, sizeof(struct ofsw))) == NULL) { - log_warn("%s: calloc failed", __func__); - goto fail; - } - if ((os->os_name = strdup(name)) == NULL) { - log_warn("%s: strdup failed", __func__); - goto fail; - } - os->os_fd = fd; - TAILQ_INIT(&os->os_ofcconns); - TAILQ_INSERT_TAIL(&ofsw_list, os, os_next); - - event_set(&os->os_evio, os->os_fd, EV_READ|EV_WRITE, ofsw_on_io, os); - event_add(&os->os_evio, NULL); - - return (os); - - fail: - if (os != NULL) - free(os->os_name); - free(os); - - return (NULL); -} - -void -ofsw_close(struct ofsw *os) -{ - struct ofcconn *oc, *oct; - - if (os->os_fd >= 0) { - close(os->os_fd); - event_del(&os->os_evio); - os->os_fd = -1; - } - TAILQ_FOREACH_SAFE(oc, &os->os_ofcconns, oc_next, oct) { - ofcconn_close(oc); - ofcconn_free(oc); - } -} - -void -ofsw_free(struct ofsw *os) -{ - if (os == NULL) - return; - - TAILQ_REMOVE(&ofsw_list, os, os_next); - free(os->os_name); - free(os); -} - -void -ofsw_on_io(int fd, short evmask, void *ctx) -{ - struct ofsw *os = ctx; - struct ofcconn *oc, *oct; - static char msg[65536];/* max size of OpenFlow message */ - ssize_t msgsz, sz; - struct ofp_header *hdr; - - if (evmask & EV_WRITE || os->os_write_ready) { - os->os_write_ready = 1; - if (ofsw_write(os, NULL) == -1) - return; - } - - if ((evmask & EV_READ) && ofsw_ofc_write_ready(os)) { - if ((msgsz = read(os->os_fd, msg, sizeof(msg))) <= 0) { - if (msgsz == -1) - log_warn("%s: %s read", __func__, os->os_name); - else - log_warnx("%s: %s closed", __func__, - os->os_name); - ofsw_close(os); - ofsw_free(os); - return; - } - hdr = (struct ofp_header *)msg; - if (hdr->oh_type != OFP_T_HELLO) { - TAILQ_FOREACH_SAFE(oc, &os->os_ofcconns, oc_next, oct) { - if ((sz = write(oc->oc_sock, msg, msgsz)) - != msgsz) { - log_warn("%s: sending a message to " - "%s failed", os->os_name, - oc->oc_name); - ofcconn_io_fail(oc); - continue; - } - oc->oc_write_ready = 0; - ofcconn_reset_event_handlers(oc); - } - } - } - ofsw_reset_event_handlers(os); - - return; -} - -int -ofsw_write(struct ofsw *os, struct ofcconn *oc0) -{ - struct ofcconn *oc = oc0; - struct ofp_header *hdr; - u_char *msg; - ssize_t sz, msglen; - int remain = 0; - unsigned char buf[65536]; - - if (!os->os_write_ready) - return (0); - - again: - if (oc != NULL) { - hdr = ibuf_seek(oc->oc_buf, 0, sizeof(*hdr)); - if (hdr == NULL) - return (0); - msglen = ntohs(hdr->oh_length); - msg = ibuf_seek(oc->oc_buf, 0, msglen); - if (msg == NULL) - return (0); - } else { - TAILQ_FOREACH(oc, &os->os_ofcconns, oc_next) { - hdr = ibuf_seek(oc->oc_buf, 0, sizeof(*hdr)); - if (hdr == NULL) - continue; - msglen = ntohs(hdr->oh_length); - msg = ibuf_seek(oc->oc_buf, 0, msglen); - if (msg != NULL) - break; - } - if (oc == NULL) - return (0); /* no message to write yet */ - } - if (hdr->oh_type != OFP_T_HELLO) { - if ((sz = write(os->os_fd, msg, msglen)) != msglen) { - if (sz == -1) - log_warn("%s: %s write failed", __func__, - os->os_name); - else - log_warn("%s: %s write partially", __func__, - os->os_name); - ofsw_close(os); - ofsw_free(os); - return (-1); - } - os->os_write_ready = 0; - } - - /* XXX preserve the remaining part */ - if ((remain = oc->oc_buf->wpos - msglen) > 0) - memcpy(buf, (caddr_t)msg + msglen, remain); - ibuf_reset(oc->oc_buf); - - /* XXX put the remaining part again */ - if (remain > 0) - ibuf_add(oc->oc_buf, buf, remain); - - if (os->os_write_ready) { - oc = NULL; - goto again; - } - - return (0); -} - -int -ofsw_ofc_write_ready(struct ofsw *os) -{ - struct ofcconn *oc; - int write_ready = 0; - - TAILQ_FOREACH(oc, &os->os_ofcconns, oc_next) { - if (oc->oc_write_ready) - write_ready = 1; - else - break; - } - if (oc != NULL) - return (0); - - return (write_ready); -} - -void -ofsw_reset_event_handlers(struct ofsw *os) -{ - short evmask = 0, oevmask; - - oevmask = event_pending(&os->os_evio, EV_READ|EV_WRITE, NULL); - - if (ofsw_ofc_write_ready(os)) - evmask |= EV_READ; - if (!os->os_write_ready) - evmask |= EV_WRITE; - - if (oevmask != evmask) { - if (oevmask) - event_del(&os->os_evio); - event_set(&os->os_evio, os->os_fd, evmask, ofsw_on_io, os); - event_add(&os->os_evio, NULL); - } -} - -int -ofsw_new_ofcconn(struct ofsw *os, struct switch_address *swa) -{ - struct ofcconn *oc = NULL; - char buf[128]; - - if ((oc = calloc(1, sizeof(struct ofcconn))) == NULL) { - log_warn("%s: calloc failed", __func__); - goto fail; - } - - if (asprintf(&oc->oc_name, "tcp:%s", - print_host(&swa->swa_addr, buf, sizeof(buf))) == -1) { - log_warn("%s: strdup failed", __func__); - goto fail; - } - if ((oc->oc_buf = ibuf_new(NULL, 0)) == NULL) { - log_warn("%s: failed to get new ibuf", __func__); - goto fail; - } - oc->oc_sw = os; - oc->oc_sock = -1; - memcpy(&oc->oc_peer, &swa->swa_addr, sizeof(oc->oc_peer)); - - if (ntohs(((struct sockaddr_in *)&oc->oc_peer)->sin_port) == 0) - ((struct sockaddr_in *)&oc->oc_peer)->sin_port = - htons(SWITCHD_CTLR_PORT); - - evtimer_set(&oc->oc_evtimer, ofcconn_on_timer, oc); - TAILQ_INSERT_TAIL(&os->os_ofcconns, oc, oc_next); - - return (ofcconn_connect(oc)); - - fail: - if (oc != NULL) { - free(oc->oc_name); - ibuf_release(oc->oc_buf); - } - free(oc); - - return (-1); -} - -int -ofcconn_connect(struct ofcconn *oc) -{ - int sock = -1; - struct timeval tv; - - if ((sock = socket(oc->oc_peer.ss_family, SOCK_STREAM | SOCK_NONBLOCK, - IPPROTO_TCP)) == -1) { - log_warn("%s: failed to open socket for channel with %s", - oc->oc_sw->os_name, oc->oc_name); - goto fail; - } - - if (connect(sock, (struct sockaddr *)&oc->oc_peer, - oc->oc_peer.ss_len) == -1) { - if (errno != EINPROGRESS) { - log_warn("%s: failed to connect channel to %s", - oc->oc_sw->os_name, oc->oc_name); - goto fail; - } - } - - oc->oc_sock = sock; - event_set(&oc->oc_evsock, oc->oc_sock, EV_READ|EV_WRITE, - ofcconn_on_sockio, oc); - event_add(&oc->oc_evsock, NULL); - - tv.tv_sec = SWITCHD_CONNECT_TIMEOUT; - tv.tv_usec = 0; - event_add(&oc->oc_evtimer, &tv); - - return (0); - - fail: - if (sock >= 0) - close(sock); - - oc->oc_conn_fails++; - ofcconn_connect_again(oc); - - return (-1); -} - -void -ofcconn_on_sockio(int fd, short evmask, void *ctx) -{ - struct ofcconn *oc = ctx; - ssize_t sz; - size_t wpos; - int err; - socklen_t optlen; - - if (evmask & EV_WRITE) { - if (oc->oc_connected == 0) { - optlen = sizeof(err); - getsockopt(oc->oc_sock, SOL_SOCKET, SO_ERROR, &err, - &optlen); - if (err != 0) { - log_warnx("%s: connection error with %s: %s", - oc->oc_sw->os_name, oc->oc_name, - strerror(err)); - oc->oc_conn_fails++; - ofcconn_close(oc); - ofcconn_connect_again(oc); - return; - } - log_info("%s: OpenFlow channel to %s connected", - oc->oc_sw->os_name, oc->oc_name); - - event_del(&oc->oc_evtimer); - oc->oc_connected = 1; - oc->oc_conn_fails = 0; - if (ofcconn_send_hello(oc) != 0) - return; - } else - oc->oc_write_ready = 1; - } - - if ((evmask & EV_READ) && ibuf_left(oc->oc_buf) > 0) { - wpos = ibuf_length(oc->oc_buf); - - /* XXX temporally fix not to access unallocated area */ - if (wpos + ibuf_left(oc->oc_buf) > oc->oc_buf->size) { - ibuf_reserve(oc->oc_buf, ibuf_left(oc->oc_buf)); - ibuf_setsize(oc->oc_buf, wpos); - } - - if ((sz = read(oc->oc_sock, ibuf_data(oc->oc_buf) + wpos, - ibuf_left(oc->oc_buf))) <= 0) { - if (sz == 0) - log_warnx("%s: %s: connection closed by peer", - oc->oc_sw->os_name, oc->oc_name); - else - log_warn("%s: %s: connection read error", - oc->oc_sw->os_name, oc->oc_name); - goto fail; - } - if (ibuf_setsize(oc->oc_buf, wpos + sz) == -1) - goto fail; - - if (ofsw_write(oc->oc_sw, oc) == -1) - return; /* oc is already freeed */ - } - ofcconn_reset_event_handlers(oc); - ofsw_reset_event_handlers(oc->oc_sw); - - return; - - fail: - ofcconn_close(oc); - ofcconn_connect_again(oc); -} - -void -ofcconn_connect_again(struct ofcconn *oc) -{ - struct timeval tv; - const int ofcconn_backoffs[] = { 1, 2, 4, 8, 16 }; - - tv.tv_sec = (oc->oc_conn_fails < (int)nitems(ofcconn_backoffs)) - ? ofcconn_backoffs[oc->oc_conn_fails] - : ofcconn_backoffs[nitems(ofcconn_backoffs) - 1]; - tv.tv_usec = 0; - event_add(&oc->oc_evtimer, &tv); -} - -void -ofcconn_on_timer(int fd, short evmask, void *ctx) -{ - struct ofcconn *oc = ctx; - - if (oc->oc_sock < 0) - ofcconn_connect(oc); - else if (!oc->oc_connected) { - log_warnx("%s: timeout connecting channel to %s", - oc->oc_sw->os_name, oc->oc_name); - ofcconn_close(oc); - oc->oc_conn_fails++; - ofcconn_connect_again(oc); - } -} - -void -ofcconn_reset_event_handlers(struct ofcconn *oc) -{ - short evmask = 0, oevmask; - - oevmask = event_pending(&oc->oc_evsock, EV_READ|EV_WRITE, NULL); - - if (ibuf_left(oc->oc_buf) > 0) - evmask |= EV_READ; - if (!oc->oc_write_ready) - evmask |= EV_WRITE; - - if (oevmask != evmask) { - if (oevmask) - event_del(&oc->oc_evsock); - if (evmask) { - event_set(&oc->oc_evsock, oc->oc_sock, evmask, - ofcconn_on_sockio, oc); - event_add(&oc->oc_evsock, NULL); - } - } -} - -void -ofcconn_io_fail(struct ofcconn *oc) -{ - ofcconn_close(oc); - ofcconn_connect_again(oc); -} - -void -ofcconn_close(struct ofcconn *oc) -{ - if (oc->oc_sock >= 0) { - event_del(&oc->oc_evsock); - close(oc->oc_sock); - oc->oc_sock = -1; - oc->oc_write_ready = 0; - } - event_del(&oc->oc_evtimer); - oc->oc_connected = 0; -} - -void -ofcconn_free(struct ofcconn *oc) -{ - if (oc == NULL) - return; - TAILQ_REMOVE(&oc->oc_sw->os_ofcconns, oc, oc_next); - ibuf_release(oc->oc_buf); - free(oc->oc_name); - free(oc); -} - -int -ofcconn_send_hello(struct ofcconn *oc) -{ - struct ofp_header hdr; - ssize_t sz; - - hdr.oh_version = OFP_V_1_3; - hdr.oh_type = OFP_T_HELLO; - hdr.oh_length = htons(sizeof(hdr)); - hdr.oh_xid = htonl(0xffffffffUL); - - sz = sizeof(hdr); - if (write(oc->oc_sock, &hdr, sz) != sz) { - log_warn("%s: %s: %s; write", __func__, oc->oc_sw->os_name, - oc->oc_name); - ofcconn_close(oc); - ofcconn_connect_again(oc); - return (-1); - } - - return (0); -} diff --git a/usr.sbin/switchd/ofp.c b/usr.sbin/switchd/ofp.c deleted file mode 100644 index bf0ef100891..00000000000 --- a/usr.sbin/switchd/ofp.c +++ /dev/null @@ -1,256 +0,0 @@ -/* $OpenBSD: ofp.c,v 1.18 2016/12/22 15:31:43 rzalamena Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "ofp10.h" -#include "switchd.h" -#include "ofp_map.h" - -int ofp_dispatch_parent(int, struct privsep_proc *, struct imsg *); -int ofp_dispatch_control(int, struct privsep_proc *, struct imsg *); -void ofp_run(struct privsep *, struct privsep_proc *, void *); -int ofp_add_device(struct switchd *, int, const char *); - -static struct privsep_proc procs[] = { - { "control", PROC_CONTROL, ofp_dispatch_control }, - { "parent", PROC_PARENT, ofp_dispatch_parent } -}; - -void -ofp(struct privsep *ps, struct privsep_proc *p) -{ - ofrelay(ps, p); - proc_run(ps, p, procs, nitems(procs), ofp_run, NULL); -} - -void -ofp_run(struct privsep *ps, struct privsep_proc *p, void *arg) -{ - struct switchd *sc = ps->ps_env; - - /* - * pledge in the ofp process: - * stdio - for malloc and basic I/O including events. - * inet - for handling tcp connections with OpenFlow peers. - * recvfd - for receiving new sockets on reload. - */ - if (pledge("stdio inet recvfd", NULL) == -1) - fatal("pledge"); - - TAILQ_INIT(&sc->sc_conns); - sc->sc_tap = -1; - - ofrelay_run(ps, p, NULL); -} - -int -ofp_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_SUM: - return (switch_dispatch_control(fd, p, imsg)); - default: - break; - } - - return (-1); -} - -int -ofp_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - struct privsep *ps = p->p_ps; - struct switchd *sc = ps->ps_env; - struct switch_client swc; - struct switch_connection *con; - - switch (imsg->hdr.type) { - case IMSG_TAPFD: - if (sc->sc_tap != -1) - close(sc->sc_tap); - sc->sc_tap = imsg->fd; - return (0); - case IMSG_CTL_CONNECT: - case IMSG_CTL_DISCONNECT: - IMSG_SIZE_CHECK(imsg, &swc); - memcpy(&swc, imsg->data, sizeof(swc)); - - if (imsg->hdr.type == IMSG_CTL_CONNECT) - ofrelay_attach(&sc->sc_server, imsg->fd, - (struct sockaddr *)&swc.swc_addr.swa_addr); - else if ((con = switchd_connbyaddr(sc, - (struct sockaddr *)&swc.swc_addr.swa_addr)) != NULL) - ofp_close(con); - return (0); - default: - break; - } - - return (-1); -} - -int -ofp_input(struct switch_connection *con, struct ibuf *ibuf) -{ - struct switchd *sc = con->con_sc; - struct ofp_header *oh; - - if ((oh = ibuf_seek(ibuf, 0, sizeof(*oh))) == NULL) { - log_debug("short header"); - return (-1); - } - - /* Check for message version match. */ - if (con->con_state > OFP_STATE_HELLO_WAIT && - con->con_version != OFP_V_0 && - oh->oh_version != con->con_version) { - log_debug("wrong version %s, expected %s", - print_map(oh->oh_version, ofp_v_map), - print_map(con->con_version, ofp_v_map)); - return (-1); - } - - /* Check the state machine to decide whether or not to allow. */ - if (con->con_state <= OFP_STATE_HELLO_WAIT && - oh->oh_type > OFP_T_ERROR) { - log_debug("expected hello, got %s", - print_map(oh->oh_type, ofp_t_map)); - return (-1); - } - - switch (oh->oh_version) { - case OFP_V_1_0: - if (ofp10_input(sc, con, oh, ibuf) != 0) - return (-1); - break; - case OFP_V_1_3: - if (ofp13_input(sc, con, oh, ibuf) != 0) - return (-1); - break; - case OFP_V_1_1: - case OFP_V_1_2: - /* FALLTHROUGH */ - default: - (void)ofp10_validate(sc, - &con->con_peer, &con->con_local, oh, ibuf); - ofp10_hello(sc, con, oh, ibuf); - return (-1); - } - - return (0); -} - -int -ofp_open(struct privsep *ps, struct switch_connection *con) -{ - struct switch_control *sw; - - /* Get associated switch, if it exists */ - sw = switch_get(con); - - log_info("%s: new connection %u.%u from switch %u", - __func__, con->con_id, con->con_instance, - sw == NULL ? 0 : sw->sw_id); - - /* Send the hello with the latest version we support. */ - if (ofp_send_hello(ps->ps_env, con, OFP_V_1_3) == -1) - return (-1); - - if (ofp_nextstate(ps->ps_env, con, OFP_STATE_HELLO_WAIT) == -1) - return (-1); - - return (0); -} - -void -ofp_close(struct switch_connection *con) -{ - ofrelay_close(con); -} - -int -ofp_nextstate(struct switchd *sc, struct switch_connection *con, - enum ofp_state state) -{ - int rv = 0; - - switch (con->con_state) { - case OFP_STATE_CLOSED: - if (state != OFP_STATE_HELLO_WAIT) - return (-1); - - break; - - case OFP_STATE_HELLO_WAIT: - if (state != OFP_STATE_FEATURE_WAIT) - return (-1); - - rv = ofp_send_featuresrequest(sc, con); - break; - - case OFP_STATE_FEATURE_WAIT: - if (state != OFP_STATE_ESTABLISHED) - return (-1); - - if (con->con_version != OFP_V_1_3) - break; - -#if 0 - /* Let's not ask this while we don't use it. */ - ofp13_flow_stats(sc, con, OFP_PORT_ANY, OFP_GROUP_ID_ANY, - OFP_TABLE_ID_ALL); - ofp13_desc(sc, con); -#endif - rv |= ofp13_table_features(sc, con, 0); - rv |= ofp13_setconfig(sc, con, OFP_CONFIG_FRAG_NORMAL, - OFP_CONTROLLER_MAXLEN_NO_BUFFER); - break; - - - case OFP_STATE_ESTABLISHED: - if (state != OFP_STATE_CLOSED) - return (-1); - - break; - - default: - return (-1); - } - - /* Set the next state. */ - con->con_state = state; - - return (rv); -} diff --git a/usr.sbin/switchd/ofp10.c b/usr.sbin/switchd/ofp10.c deleted file mode 100644 index e1dbc724c10..00000000000 --- a/usr.sbin/switchd/ofp10.c +++ /dev/null @@ -1,475 +0,0 @@ -/* $OpenBSD: ofp10.c,v 1.21 2019/05/05 21:33:00 akoshibe Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "ofp10.h" -#include "switchd.h" -#include "ofp_map.h" - - -int ofp10_packet_match(struct packet *, struct ofp10_match *, unsigned int); - -int ofp10_features_reply(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp10_validate_features_reply(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp10_echo_request(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp10_validate_error(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp10_error(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp10_validate_packet_in(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp10_packet_in(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp10_validate_packet_out(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); - -struct ofp_callback ofp10_callbacks[] = { - { OFP10_T_HELLO, ofp10_hello, ofp_validate_hello }, - { OFP10_T_ERROR, NULL, ofp10_validate_error }, - { OFP10_T_ECHO_REQUEST, ofp10_echo_request, NULL }, - { OFP10_T_ECHO_REPLY, NULL, NULL }, - { OFP10_T_EXPERIMENTER, NULL, NULL }, - { OFP10_T_FEATURES_REQUEST, NULL, NULL }, - { OFP10_T_FEATURES_REPLY, ofp10_features_reply, - ofp10_validate_features_reply }, - { OFP10_T_GET_CONFIG_REQUEST, NULL, NULL }, - { OFP10_T_GET_CONFIG_REPLY, NULL, NULL }, - { OFP10_T_SET_CONFIG, NULL, NULL }, - { OFP10_T_PACKET_IN, ofp10_packet_in, ofp10_validate_packet_in }, - { OFP10_T_FLOW_REMOVED, NULL, NULL }, - { OFP10_T_PORT_STATUS, NULL, NULL }, - { OFP10_T_PACKET_OUT, NULL, ofp10_validate_packet_out }, - { OFP10_T_FLOW_MOD, NULL, NULL }, - { OFP10_T_PORT_MOD, NULL, NULL }, - { OFP10_T_STATS_REQUEST, NULL, NULL }, - { OFP10_T_STATS_REPLY, NULL, NULL }, - { OFP10_T_BARRIER_REQUEST, NULL, NULL }, - { OFP10_T_BARRIER_REPLY, NULL, NULL }, - { OFP10_T_QUEUE_GET_CONFIG_REQUEST, NULL, NULL }, - { OFP10_T_QUEUE_GET_CONFIG_REPLY, NULL, NULL } -}; - -int -ofp10_validate(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - uint8_t type; - - if (ofp_validate_header(sc, src, dst, oh, OFP_V_1_0) != 0) { - log_debug("\tinvalid header"); - return (-1); - } - if (ibuf == NULL) { - /* The response packet buffer is optional */ - return (0); - } - type = oh->oh_type; - if (ofp10_callbacks[type].validate != NULL && - ofp10_callbacks[type].validate(sc, src, dst, oh, ibuf) != 0) { - log_debug("\tinvalid packet"); - return (-1); - } - return (0); -} - -int -ofp10_validate_packet_in(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp10_packet_in *pin; - uint8_t *p; - size_t len, plen; - off_t off; - - off = 0; - if ((pin = ibuf_seek(ibuf, off, sizeof(*pin))) == NULL) - return (-1); - log_debug("\tbuffer %d port %s " - "length %u reason %u", - ntohl(pin->pin_buffer_id), - print_map(ntohs(pin->pin_port), ofp10_port_map), - ntohs(pin->pin_total_len), - pin->pin_reason); - off += sizeof(*pin); - - len = ntohs(pin->pin_total_len); - plen = ibuf_length(ibuf) - off; - - if (plen < len) { - log_debug("\ttruncated packet %zu < %zu", plen, len); - - /* Buffered packets can be truncated */ - if (pin->pin_buffer_id != OFP_PKTOUT_NO_BUFFER) - len = plen; - else - return (-1); - } - if ((p = ibuf_seek(ibuf, off, len)) == NULL) - return (-1); - if (sc->sc_tap != -1) - (void)write(sc->sc_tap, p, len); - - return (0); -} - -int -ofp10_validate_packet_out(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp10_packet_out *pout; - size_t len; - off_t off; - struct ofp_action_header *ah; - struct ofp10_action_output *ao; - - off = 0; - if ((pout = ibuf_seek(ibuf, off, sizeof(*pout))) == NULL) { - log_debug("%s: seek failed: length %zd", - __func__, ibuf_length(ibuf)); - return (-1); - } - log_debug("\tbuffer %d port %s " - "actions length %u", - ntohl(pout->pout_buffer_id), - print_map(ntohs(pout->pout_port), ofp10_port_map), - ntohs(pout->pout_actions_len)); - len = ntohs(pout->pout_actions_len); - - off += sizeof(*pout); - while ((ah = ibuf_seek(ibuf, off, len)) != NULL && - ntohs(ah->ah_len) >= (uint16_t)sizeof(*ah)) { - switch (ntohs(ah->ah_type)) { - case OFP10_ACTION_OUTPUT: - ao = (struct ofp10_action_output *)ah; - log_debug("\t\taction type %s length %d " - "port %s max length %d", - print_map(ntohs(ao->ao_type), ofp10_action_map), - ntohs(ao->ao_len), - print_map(ntohs(ao->ao_port), ofp10_port_map), - ntohs(ao->ao_max_len)); - break; - default: - log_debug("\t\taction type %s length %d", - print_map(ntohs(ah->ah_type), ofp10_action_map), - ntohs(ah->ah_len)); - break; - } - if (pout->pout_buffer_id == (uint32_t)-1) - break; - off += ntohs(ah->ah_len); - } - - return (0); -} - -int -ofp10_validate_error(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_error *err; - off_t off; - const char *code; - - off = 0; - if ((err = ibuf_seek(ibuf, off, sizeof(*err))) == NULL) { - log_debug("%s: seek failed: length %zd", - __func__, ibuf_length(ibuf)); - return (-1); - } - - switch (ntohs(err->err_type)) { - case OFP10_ERRTYPE_FLOW_MOD_FAILED: - code = print_map(ntohs(err->err_code), ofp10_errflowmod_map); - break; - default: - code = NULL; - break; - } - - log_debug("\terror type %s code %u%s%s", - print_map(ntohs(err->err_type), ofp10_errtype_map), - ntohs(err->err_code), - code == NULL ? "" : ": ", - code == NULL ? "" : code); - - return (0); -} - -int -ofp10_input(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - if (ofp10_validate(sc, &con->con_peer, &con->con_local, oh, ibuf) != 0) - return (-1); - - if (ofp10_callbacks[oh->oh_type].cb == NULL) { - log_debug("message not supported: %s", - print_map(oh->oh_type, ofp10_t_map)); - return (-1); - } - if (ofp10_callbacks[oh->oh_type].cb(sc, con, oh, ibuf) != 0) - return (-1); - - return (0); -} - -int -ofp10_hello(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - if (switch_add(con) == NULL) { - log_debug("%s: failed to add switch", __func__); - return (-1); - } - - if (ofp_recv_hello(sc, con, oh, ibuf) == -1) - return (-1); - - return (ofp_nextstate(sc, con, OFP_STATE_FEATURE_WAIT)); -} - -int -ofp10_features_reply(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - return (ofp_nextstate(sc, con, OFP_STATE_ESTABLISHED)); -} - -int -ofp10_validate_features_reply(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_switch_features *swf; - struct ofp10_phy_port *swp; - off_t poff; - int portslen; - char *mac; - - if ((swf = ibuf_seek(ibuf, 0, sizeof(*swf))) == NULL) - return (-1); - - log_debug("\tdatapath_id %#016llx nbuffers %u ntables %d " - "capabilities %#08x actions %#08x", - be64toh(swf->swf_datapath_id), ntohl(swf->swf_nbuffers), - swf->swf_ntables, ntohl(swf->swf_capabilities), - ntohl(swf->swf_actions)); - - poff = sizeof(*swf); - portslen = ntohs(oh->oh_length) - sizeof(*swf); - if (portslen <= 0) - return (0); - - while (portslen > 0) { - if ((swp = ibuf_seek(ibuf, poff, sizeof(*swp))) == NULL) - return (-1); - - mac = ether_ntoa((void *)swp->swp_macaddr); - log_debug("no %s macaddr %s name %s config %#08x state %#08x " - "cur %#08x advertised %#08x supported %#08x peer %#08x", - print_map(ntohs(swp->swp_number), ofp10_port_map), mac, - swp->swp_name, swp->swp_config, swp->swp_state, - swp->swp_cur, swp->swp_advertised, swp->swp_supported, - swp->swp_peer); - - portslen -= sizeof(*swp); - poff += sizeof(*swp); - } - - return (0); -} - -int -ofp10_echo_request(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - /* Echo reply */ - oh->oh_type = OFP10_T_ECHO_REPLY; - if (ofp10_validate(sc, &con->con_local, &con->con_peer, oh, NULL) != 0) - return (-1); - ofp_output(con, oh, NULL); - - return (0); -} - -int -ofp10_packet_match(struct packet *pkt, struct ofp10_match *m, uint32_t flags) -{ - struct ether_header *eh = pkt->pkt_eh; - - memset(m, 0, sizeof(*m)); - m->m_wildcards = htonl(~flags); - - if ((flags & (OFP10_WILDCARD_DL_SRC|OFP10_WILDCARD_DL_DST)) && - (eh == NULL)) - return (-1); - - if (flags & OFP10_WILDCARD_DL_SRC) - memcpy(m->m_dl_src, eh->ether_shost, ETHER_ADDR_LEN); - if (flags & OFP10_WILDCARD_DL_DST) - memcpy(m->m_dl_dst, eh->ether_dhost, ETHER_ADDR_LEN); - - return (0); -} - -int -ofp10_packet_in(struct switchd *sc, struct switch_connection *con, - struct ofp_header *ih, struct ibuf *ibuf) -{ - struct ofp10_packet_in *pin; - struct ofp10_packet_out *pout; - struct ofp10_action_output *ao; - struct ofp10_flow_mod *fm; - struct ofp_header *oh; - struct packet pkt; - struct ibuf *obuf = NULL; - int ret = -1; - size_t len; - uint32_t srcport, dstport; - int addflow = 0; - int addpacket = 0; - - if ((pin = ibuf_getdata(ibuf, sizeof(*pin))) == NULL) - return (-1); - - memset(&pkt, 0, sizeof(pkt)); - len = ntohs(pin->pin_total_len); - - srcport = ntohs(pin->pin_port); - - if (packet_ether_input(ibuf, len, &pkt) == -1 && - pin->pin_buffer_id == htonl(OFP_PKTOUT_NO_BUFFER)) - return(-1); - - if (packet_input(sc, con->con_switch, - srcport, &dstport, &pkt) == -1 || - (dstport > OFP10_PORT_MAX && - dstport != OFP10_PORT_LOCAL && - dstport != OFP10_PORT_CONTROLLER)) { - /* fallback to flooding */ - dstport = OFP10_PORT_FLOOD; - } else if (srcport == dstport) { - /* - * silently drop looping packet - * (don't use OFP10_PORT_INPUT here) - */ - ret = 0; - goto done; - } else { - addflow = 1; - } - - if ((obuf = ibuf_static()) == NULL) - goto done; - - again: - if (addflow) { - if ((fm = ibuf_advance(obuf, sizeof(*fm))) == NULL) - goto done; - - ofp10_packet_match(&pkt, &fm->fm_match, OFP10_WILDCARD_DL_DST); - - oh = &fm->fm_oh; - fm->fm_cookie = 0; /* XXX should we set a cookie? */ - fm->fm_command = htons(OFP_FLOWCMD_ADD); - fm->fm_idle_timeout = htons(sc->sc_cache_timeout); - fm->fm_hard_timeout = 0; /* permanent */ - fm->fm_priority = 0; - fm->fm_buffer_id = pin->pin_buffer_id; - fm->fm_flags = htons(OFP_FLOWFLAG_SEND_FLOW_REMOVED); - if (pin->pin_buffer_id == htonl(OFP_PKTOUT_NO_BUFFER)) - addpacket = 1; - } else { - if ((pout = ibuf_advance(obuf, sizeof(*pout))) == NULL) - goto done; - - oh = &pout->pout_oh; - pout->pout_buffer_id = pin->pin_buffer_id; - pout->pout_port = pin->pin_port; - pout->pout_actions_len = htons(sizeof(*ao)); - - if (pin->pin_buffer_id == htonl(OFP_PKTOUT_NO_BUFFER)) - addpacket = 1; - } - - if ((ao = ibuf_advance(obuf, sizeof(*ao))) == NULL) - goto done; - ao->ao_type = htons(OFP_ACTION_OUTPUT); - ao->ao_len = htons(sizeof(*ao)); - ao->ao_port = htons((uint16_t)dstport); - ao->ao_max_len = 0; - - /* Add optional packet payload to packet-out. */ - if (addflow == 0 && addpacket && - imsg_add(obuf, pkt.pkt_buf, pkt.pkt_len) == -1) - goto done; - - /* Set output header */ - memcpy(oh, ih, sizeof(*oh)); - oh->oh_length = htons(ibuf_length(obuf)); - oh->oh_type = addflow ? OFP10_T_FLOW_MOD : OFP10_T_PACKET_OUT; - oh->oh_xid = htonl(con->con_xidnxt++); - - if (ofp10_validate(sc, &con->con_local, &con->con_peer, oh, obuf) != 0) - goto done; - - ofp_output(con, NULL, obuf); - - if (addflow && addpacket) { - /* loop to output the packet again */ - addflow = 0; - if ((obuf = ibuf_static()) == NULL) - goto done; - goto again; - } - - ret = 0; - done: - ibuf_release(obuf); - return (ret); -} diff --git a/usr.sbin/switchd/ofp10.h b/usr.sbin/switchd/ofp10.h deleted file mode 100644 index 8db1e78d879..00000000000 --- a/usr.sbin/switchd/ofp10.h +++ /dev/null @@ -1,184 +0,0 @@ -/* $OpenBSD: ofp10.h,v 1.2 2016/09/30 12:48:27 reyk Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _NET_OFP10_H_ -#define _NET_OFP10_H_ - -#include - -/* OpenFlow message type */ -#define OFP10_T_HELLO 0 /* Hello */ -#define OFP10_T_ERROR 1 /* Error */ -#define OFP10_T_ECHO_REQUEST 2 /* Echo Request */ -#define OFP10_T_ECHO_REPLY 3 /* Echo Reply */ -#define OFP10_T_EXPERIMENTER 4 /* Vendor/Experimenter */ -#define OFP10_T_FEATURES_REQUEST 5 /* Features Request (switch) */ -#define OFP10_T_FEATURES_REPLY 6 /* Features Reply (switch) */ -#define OFP10_T_GET_CONFIG_REQUEST 7 /* Get Config Request (switch) */ -#define OFP10_T_GET_CONFIG_REPLY 8 /* Get Config Reply (switch) */ -#define OFP10_T_SET_CONFIG 9 /* Set Config (switch) */ -#define OFP10_T_PACKET_IN 10 /* Packet In (async) */ -#define OFP10_T_FLOW_REMOVED 11 /* Flow Removed (async) */ -#define OFP10_T_PORT_STATUS 12 /* Port Status (async) */ -#define OFP10_T_PACKET_OUT 13 /* Packet Out (controller) */ -#define OFP10_T_FLOW_MOD 14 /* Flow Mod (controller) */ -#define OFP10_T_PORT_MOD 16 /* Port Mod (controller) */ -#define OFP10_T_STATS_REQUEST 17 /* Stats Request */ -#define OFP10_T_STATS_REPLY 18 /* Stats Reply */ -#define OFP10_T_BARRIER_REQUEST 19 /* Barrier Request */ -#define OFP10_T_BARRIER_REPLY 20 /* Barrier Reply */ -#define OFP10_T_QUEUE_GET_CONFIG_REQUEST 21 /* Queue Get Config Request */ -#define OFP10_T_QUEUE_GET_CONFIG_REPLY 22 /* Queue Get Config Reply */ -#define OFP10_T_TYPE_MAX 23 - -/* Ports */ -#define OFP10_PORT_MAX 0xff00 /* Maximum number of physical ports */ -#define OFP10_PORT_INPUT 0xfff8 /* Send back to input port */ -#define OFP10_PORT_FLOWTABLE 0xfff9 /* Perform actions in flow table */ -#define OFP10_PORT_NORMAL 0xfffa /* Let switch decide */ -#define OFP10_PORT_FLOOD 0xfffb /* All non-block ports except input */ -#define OFP10_PORT_ALL 0xfffc /* All ports except input */ -#define OFP10_PORT_CONTROLLER 0xfffd /* Send to controller */ -#define OFP10_PORT_LOCAL 0xfffe /* Local virtual OpenFlow port */ -#define OFP10_PORT_ANY 0xffff /* No port */ - -/* Switch port description */ -struct ofp10_phy_port { - uint16_t swp_number; - uint8_t swp_macaddr[ETHER_ADDR_LEN]; - char swp_name[OFP_IFNAMSIZ]; - uint32_t swp_config; /* Configuration flags */ - uint32_t swp_state; /* State flags */ - uint32_t swp_cur; /* Current features */ - uint32_t swp_advertised; /* Advertised by the port */ - uint32_t swp_supported; /* Supported by the port */ - uint32_t swp_peer; /* Advertised by peer */ -}; - -/* Packet-In Message */ -struct ofp10_packet_in { - struct ofp_header pin_oh; /* OpenFlow header */ - uint32_t pin_buffer_id; - uint16_t pin_total_len; - uint16_t pin_port; - uint8_t pin_reason; - uint8_t pin_pad; - uint8_t pin_data[0]; -} __packed; - -/* Actions */ -#define OFP10_ACTION_OUTPUT 0 /* Output to switch port */ -#define OFP10_ACTION_SET_VLAN_VID 1 /* Set the 802.1q VLAN id */ -#define OFP10_ACTION_SET_VLAN_PCP 2 /* Set the 802.1q priority */ -#define OFP10_ACTION_STRIP_VLAN 3 /* Strip the 802.1q header */ -#define OFP10_ACTION_SET_DL_SRC 4 /* Ethernet src address */ -#define OFP10_ACTION_SET_DL_DST 5 /* Ethernet dst address */ -#define OFP10_ACTION_SET_NW_SRC 6 /* IP src address */ -#define OFP10_ACTION_SET_NW_DST 7 /* IP dst address */ -#define OFP10_ACTION_SET_NW_TOS 8 /* IP TOS */ -#define OFP10_ACTION_SET_TP_SRC 9 /* TCP/UDP src port */ -#define OFP10_ACTION_SET_TP_DST 10 /* TCP/UDP dst port */ -#define OFP10_ACTION_ENQUEUE 11 /* Output to queue */ -#define OFP10_ACTION_EXPERIMENTER 0xffff /* Vendor-specific action */ - -/* Output Action */ -struct ofp10_action_output { - uint16_t ao_type; - uint16_t ao_len; - uint16_t ao_port; - uint16_t ao_max_len; -} __packed; - -/* Packet-Out Message */ -struct ofp10_packet_out { - struct ofp_header pout_oh; /* OpenFlow header */ - uint32_t pout_buffer_id; - uint16_t pout_port; - uint16_t pout_actions_len; - struct ofp_action_header pout_actions[0]; - /* Followed by optional packet data if buffer_id == 0xffffffff */ -} __packed; - -/* Flow matching wildcards */ -#define OFP10_WILDCARD_IN_PORT 0x00000001 /* Switch input port */ -#define OFP10_WILDCARD_DL_VLAN 0x00000002 /* VLAN id */ -#define OFP10_WILDCARD_DL_SRC 0x00000004 /* Ethernet src address */ -#define OFP10_WILDCARD_DL_DST 0x00000008 /* Ethernet dst address */ -#define OFP10_WILDCARD_DL_TYPE 0x00000010 /* Ethernet frame type */ -#define OFP10_WILDCARD_NW_PROTO 0x00000020 /* IPv4 protocol */ -#define OFP10_WILDCARD_TP_SRC 0x00000040 /* TCP/UDP source port */ -#define OFP10_WILDCARD_TP_DST 0x00000080 /* TCP/UDP destination port */ -#define OFP10_WILDCARD_NW_SRC 0x00003f00 /* IPv4 source address */ -#define OFP10_WILDCARD_NW_SRC_S 8 -#define OFP10_WILDCARD_NW_DST 0x000fc000 /* IPv4 destination address */ -#define OFP10_WILDCARD_NW_DST_S 14 -#define OFP10_WILDCARD_DL_VLANPCP 0x00100000 /* VLAN prio */ -#define OFP10_WILDCARD_NW_TOS 0x00200000 /* IPv4 ToS/DSCP */ -#define OFP10_WILDCARD_MASK 0x003fffff /* All wildcard flags */ - -/* Flow matching */ -struct ofp10_match { - uint32_t m_wildcards; /* Wildcard options */ - uint16_t m_in_port; /* Switch port */ - uint8_t m_dl_src[ETHER_ADDR_LEN]; /* Ether src addr */ - uint8_t m_dl_dst[ETHER_ADDR_LEN]; /* Ether dst addr */ - uint16_t m_dl_vlan; /* Input VLAN id */ - uint8_t m_dl_vlan_pcp; /* Input VLAN prio */ - uint8_t m_pad1[1]; - uint16_t m_dl_type; /* Ether type */ - uint8_t m_nw_tos; /* IPv4 ToS/DSCP */ - uint8_t m_nw_proto; /* IPv4 Proto */ - uint8_t m_pad2[2]; - uint32_t m_nw_src; /* IPv4 source */ - uint32_t m_nw_dst; /* IPv4 destination */ - uint16_t m_tp_src; /* TCP/UDP src port */ - uint16_t m_tp_dst; /* TCP/UDP dst port */ -} __packed; - -/* Flow modification message */ -struct ofp10_flow_mod { - struct ofp_header fm_oh; /* OpenFlow header */ - struct ofp10_match fm_match; - uint64_t fm_cookie; - uint16_t fm_command; - uint16_t fm_idle_timeout; - uint16_t fm_hard_timeout; - uint16_t fm_priority; - uint32_t fm_buffer_id; - uint16_t fm_port; - uint16_t fm_flags; - struct ofp_action_header fm_actions[0]; -} __packed; - -/* Error types */ -#define OFP10_ERRTYPE_HELLO_FAILED 0 /* Hello protocol failed */ -#define OFP10_ERRTYPE_BAD_REQUEST 1 /* Request was not understood */ -#define OFP10_ERRTYPE_BAD_ACTION 2 /* Error in action */ -#define OFP10_ERRTYPE_FLOW_MOD_FAILED 3 /* Problem modifying flow */ -#define OFP10_ERRTYPE_PORT_MOD_FAILED 4 /* Port mod request failed */ -#define OFP10_ERRTYPE_QUEUE_OP_FAILED 5 /* Queue operation failed */ - -/* FLOW MOD error codes */ -#define OFP10_ERRFLOWMOD_ALL_TABLES_FULL 0 /* Not added, full tables */ -#define OFP10_ERRFLOWMOD_OVERLAP 1 /* Overlapping flow */ -#define OFP10_ERRFLOWMOD_EPERM 2 /* Permissions error */ -#define OFP10_ERRFLOWMOD_BAD_TIMEOUT 3 /* non-zero idle/hardtimeout */ -#define OFP10_ERRFLOWMOD_BAD_COMMAND 4 /* Unknown command */ -#define OFP10_ERRFLOWMOD_UNSUPPORTED 5 /* Unsupported action list */ - -#endif /* _NET_OPF_H_ */ diff --git a/usr.sbin/switchd/ofp13.c b/usr.sbin/switchd/ofp13.c deleted file mode 100644 index 721302451a7..00000000000 --- a/usr.sbin/switchd/ofp13.c +++ /dev/null @@ -1,2258 +0,0 @@ -/* $OpenBSD: ofp13.c,v 1.47 2019/11/27 17:37:32 akoshibe Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * Copyright (c) 2016 Rafael Zalamena - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" -#include "ofp_map.h" - -int ofp13_echo_request(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp13_validate_features_reply(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp13_features_reply(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp13_validate_error(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp13_validate_action(struct switchd *, struct ofp_header *, - struct ibuf *, off_t *, struct ofp_action_header *); -int ofp13_validate_instruction(struct switchd *, struct ofp_header *, - struct ibuf *, off_t *, struct ofp_instruction *); -int ofp13_validate_flow_mod(struct switchd *, struct sockaddr_storage *, - struct sockaddr_storage *, struct ofp_header *, struct ibuf *); -int ofp13_validate_oxm_basic(struct ibuf *, off_t, int, uint8_t); -int ofp13_validate_oxm(struct switchd *, struct ofp_ox_match *, - struct ofp_header *, struct ibuf *, off_t); -int ofp13_validate_packet_in(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp13_packet_match(struct ibuf *, struct packet *, struct ofp_match *); -int ofp13_packet_in(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp13_flow_removed(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp13_tableproperties(struct switch_connection *, struct ibuf *, - off_t, size_t, int); -int ofp13_multipart_reply(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp13_validate_tableproperty(struct ibuf *, off_t, int); -int ofp13_multipart_reply_validate(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp13_validate_packet_out(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); - -struct ofp_multipart * - ofp13_multipart_request(struct switch_connection *, struct ibuf *, - uint16_t, uint16_t); -int ofp13_multipart_request_validate(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); - -int ofp13_error(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *, uint16_t, uint16_t); - -struct ofp_group_mod * - ofp13_group(struct switch_connection *, struct ibuf *, - uint32_t, uint16_t, uint8_t); -struct ofp_bucket * - ofp13_bucket(struct ibuf *, uint16_t, uint32_t, uint32_t); - -int ofp13_setconfig_validate(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); - -int ofp13_switchconfigure(struct switchd *, struct switch_connection *); -int ofp13_getflowtable(struct switch_connection *); - -struct ofp_callback ofp13_callbacks[] = { - { OFP_T_HELLO, ofp13_hello, ofp_validate_hello }, - { OFP_T_ERROR, NULL, ofp13_validate_error }, - { OFP_T_ECHO_REQUEST, ofp13_echo_request, NULL }, - { OFP_T_ECHO_REPLY, NULL, NULL }, - { OFP_T_EXPERIMENTER, NULL, NULL }, - { OFP_T_FEATURES_REQUEST, NULL, NULL }, - { OFP_T_FEATURES_REPLY, ofp13_features_reply, - ofp13_validate_features_reply }, - { OFP_T_GET_CONFIG_REQUEST, NULL, NULL }, - { OFP_T_GET_CONFIG_REPLY, NULL, NULL }, - { OFP_T_SET_CONFIG, NULL, ofp13_setconfig_validate }, - { OFP_T_PACKET_IN, ofp13_packet_in, - ofp13_validate_packet_in }, - { OFP_T_FLOW_REMOVED, ofp13_flow_removed, NULL }, - { OFP_T_PORT_STATUS, NULL, NULL }, - { OFP_T_PACKET_OUT, NULL, ofp13_validate_packet_out }, - { OFP_T_FLOW_MOD, NULL, ofp13_validate_flow_mod }, - { OFP_T_GROUP_MOD, NULL, NULL }, - { OFP_T_PORT_MOD, NULL, NULL }, - { OFP_T_TABLE_MOD, NULL, NULL }, - { OFP_T_MULTIPART_REQUEST, NULL, - ofp13_multipart_request_validate }, - { OFP_T_MULTIPART_REPLY, ofp13_multipart_reply, - ofp13_multipart_reply_validate }, - { OFP_T_BARRIER_REQUEST, NULL, NULL }, - { OFP_T_BARRIER_REPLY, NULL, NULL }, - { OFP_T_QUEUE_GET_CONFIG_REQUEST, NULL, NULL }, - { OFP_T_QUEUE_GET_CONFIG_REPLY, NULL, NULL }, - { OFP_T_ROLE_REQUEST, NULL, NULL }, - { OFP_T_ROLE_REPLY, NULL, NULL }, - { OFP_T_GET_ASYNC_REQUEST, NULL, NULL }, - { OFP_T_GET_ASYNC_REPLY, NULL, NULL }, - { OFP_T_SET_ASYNC, NULL, NULL }, - { OFP_T_METER_MOD, NULL, NULL }, -}; - -int -ofp13_validate(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - uint8_t type; - - if (ofp_validate_header(sc, src, dst, oh, OFP_V_1_3) != 0) { - log_debug("\tinvalid header"); - return (-1); - } - if (ibuf == NULL) { - /* The response packet buffer is optional */ - return (0); - } - type = oh->oh_type; - if (ofp13_callbacks[type].validate != NULL && - ofp13_callbacks[type].validate(sc, src, dst, oh, ibuf) != 0) { - log_debug("\tinvalid packet"); - return (-1); - } - return (0); -} - -int -ofp13_validate_oxm_basic(struct ibuf *ibuf, off_t off, int hasmask, - uint8_t type) -{ - uint8_t *ui8; - uint16_t *ui16; - uint32_t *ui32; - uint64_t *ui64; - int i, len; - char hex[8], buf[64], maskbuf[64]; - - switch (type) { - case OFP_XM_T_IN_PORT: - case OFP_XM_T_IN_PHY_PORT: - case OFP_XM_T_MPLS_LABEL: - if (hasmask) - return (-1); - if ((ui32 = ibuf_seek(ibuf, off, sizeof(*ui32))) == NULL) - return (-1); - - log_debug("\t\t%u", ntohl(*ui32)); - break; - - case OFP_XM_T_META: - case OFP_XM_T_TUNNEL_ID: - len = sizeof(*ui64); - if (hasmask) - len *= 2; - - if ((ui64 = ibuf_seek(ibuf, off, len)) == NULL) - return (-1); - - if (hasmask) - log_debug("\t\t%llu mask %#16llx", - be64toh(*ui64), be64toh(*(ui64 + 1))); - else - log_debug("\t\t%llu", be64toh(*ui64)); - break; - - case OFP_XM_T_ARP_SHA: - case OFP_XM_T_ARP_THA: - case OFP_XM_T_IPV6_ND_SLL: - case OFP_XM_T_IPV6_ND_TLL: - if (hasmask) - return (-1); - if ((ui8 = ibuf_seek(ibuf, off, ETHER_ADDR_LEN)) == NULL) - return (-1); - - buf[0] = 0; - for (i = 0; i < ETHER_ADDR_LEN; i++) { - snprintf(hex, sizeof(hex), "%02x", *(ui8 + i)); - strlcat(buf, hex, sizeof(buf)); - } - - log_debug("\t\t%s", buf); - break; - - case OFP_XM_T_ETH_DST: - case OFP_XM_T_ETH_SRC: - len = ETHER_ADDR_LEN; - if (hasmask) - len *= 2; - - if ((ui8 = ibuf_seek(ibuf, off, len)) == NULL) - return (-1); - - buf[0] = 0; - for (i = 0; i < ETHER_ADDR_LEN; i++) { - snprintf(hex, sizeof(hex), "%02x", *(ui8 + i)); - strlcat(buf, hex, sizeof(buf)); - } - - if (hasmask) { - maskbuf[0] = 0; - for (i = 0; i < ETHER_ADDR_LEN; i++) { - snprintf(hex, sizeof(hex), "%02x", *(ui8 + - (i + ETHER_ADDR_LEN))); - strlcat(maskbuf, hex, sizeof(maskbuf)); - } - log_debug("\t\t%s mask %s", buf, maskbuf); - } else - log_debug("\t\t%s", buf); - break; - - case OFP_XM_T_ETH_TYPE: - if (hasmask) - return (-1); - len = sizeof(*ui16); - if ((ui16 = ibuf_seek(ibuf, off, len)) == NULL) - return (-1); - log_debug("\t\t0x%04x", ntohs(*ui16)); - break; - - case OFP_XM_T_TCP_SRC: - case OFP_XM_T_TCP_DST: - case OFP_XM_T_UDP_SRC: - case OFP_XM_T_UDP_DST: - case OFP_XM_T_SCTP_SRC: - case OFP_XM_T_SCTP_DST: - case OFP_XM_T_ARP_OP: - if (hasmask) - return (-1); - if ((ui16 = ibuf_seek(ibuf, off, sizeof(*ui16))) == NULL) - return (-1); - - log_debug("\t\t%d", ntohs(*ui16)); - break; - - case OFP_XM_T_VLAN_VID: - case OFP_XM_T_IPV6_EXTHDR: - len = sizeof(*ui16); - if (hasmask) - len *= 2; - - if ((ui16 = ibuf_seek(ibuf, off, len)) == NULL) - return (-1); - - if (type == OFP_XM_T_VLAN_VID) { - /* Remove the VID present bit to display. */ - if (hasmask) - log_debug("\t\t%d mask %#04x", - ntohs(*ui16) & ~OFP_XM_VID_PRESENT, - ntohs(*(ui16 + 1))); - else - log_debug("\t\t%d", - ntohs(*ui16) & ~OFP_XM_VID_PRESENT); - break; - } - - if (hasmask) - log_debug("\t\t%d mask %#04x", - ntohs(*ui16), ntohs(*(ui16 + 1))); - else - log_debug("\t\t%d", ntohs(*ui16)); - break; - - case OFP_XM_T_IP_DSCP: - case OFP_XM_T_IP_ECN: - case OFP_XM_T_IP_PROTO: - case OFP_XM_T_ICMPV4_TYPE: - case OFP_XM_T_ICMPV4_CODE: - case OFP_XM_T_ICMPV6_TYPE: - case OFP_XM_T_ICMPV6_CODE: - case OFP_XM_T_MPLS_TC: - case OFP_XM_T_MPLS_BOS: - if (hasmask) - return (-1); - if ((ui8 = ibuf_seek(ibuf, off, sizeof(*ui8))) == NULL) - return (-1); - - log_debug("\t\t%#02x", *ui8); - break; - - case OFP_XM_T_IPV4_SRC: - case OFP_XM_T_IPV4_DST: - case OFP_XM_T_ARP_SPA: - case OFP_XM_T_ARP_TPA: - case OFP_XM_T_IPV6_FLABEL: - len = sizeof(*ui32); - if (hasmask) - len *= 2; - - if ((ui32 = ibuf_seek(ibuf, off, len)) == NULL) - return (-1); - - if (hasmask) - log_debug("\t\t%#08x mask %#08x", - ntohl(*ui32), ntohl(*(ui32 + 1))); - else - log_debug("\t\t%#08x", ntohl(*ui32)); - break; - - case OFP_XM_T_IPV6_ND_TARGET: - if (hasmask) - return (-1); - if ((ui8 = ibuf_seek(ibuf, off, - sizeof(struct in6_addr))) == NULL) - return (-1); - - buf[0] = 0; - for (i = 0; i < (int)sizeof(struct in6_addr); i++) { - snprintf(hex, sizeof(hex), "%02x", *(ui8 + i)); - strlcat(buf, hex, sizeof(buf)); - } - - log_debug("\t\t%s", buf); - break; - - case OFP_XM_T_IPV6_SRC: - case OFP_XM_T_IPV6_DST: - len = sizeof(struct in6_addr); - if (hasmask) - len *= 2; - - if ((ui8 = ibuf_seek(ibuf, off, len)) == NULL) - return (-1); - - buf[0] = 0; - for (i = 0; i < (int)sizeof(struct in6_addr); i++) { - snprintf(hex, sizeof(hex), "%02x", *(ui8 + i)); - strlcat(buf, hex, sizeof(buf)); - } - - if (hasmask) { - maskbuf[0] = 0; - for (i = 0; i < (int)sizeof(struct in6_addr); i++) { - snprintf(hex, sizeof(hex), "%02x", *(ui8 + - (i + sizeof(struct in6_addr)))); - strlcat(maskbuf, hex, sizeof(maskbuf)); - } - log_debug("\t\t%s mask %s", buf, maskbuf); - } else - log_debug("\t\t%s", buf); - break; - - case OFP_XM_T_PBB_ISID: - /* TODO teach me how to read 24 bits and convert to be. */ - break; - - default: - log_debug("\t\tUnknown type"); - return (-1); - } - - return (0); -} - -int -ofp13_validate_oxm(struct switchd *sc, struct ofp_ox_match *oxm, - struct ofp_header *oh, struct ibuf *ibuf, off_t off) -{ - uint16_t class; - uint8_t type; - int hasmask; - - /* match element is always followed by data */ - if (oxm->oxm_length == 0) - return (0); - - type = OFP_OXM_GET_FIELD(oxm); - hasmask = OFP_OXM_GET_HASMASK(oxm); - class = ntohs(oxm->oxm_class); - off += sizeof(*oxm); - - log_debug("\tox match class %s type %s hasmask %s length %u", - print_map(class, ofp_oxm_c_map), - print_map(type, ofp_xm_t_map), - hasmask ? "yes" : "no", - oxm->oxm_length); - - switch (class) { - case OFP_OXM_C_NXM_0: - case OFP_OXM_C_NXM_1: - /* TODO teach me how to read NXM_*. */ - break; - - case OFP_OXM_C_OPENFLOW_BASIC: - return (ofp13_validate_oxm_basic(ibuf, off, hasmask, type)); - - case OFP_OXM_C_OPENFLOW_EXPERIMENTER: - /* Implementation dependent: there is nothing to do here. */ - break; - - default: - return (-1); - } - - return (0); -} - -int -ofp13_validate_packet_in(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_packet_in *pin; - struct ofp_match *om; - struct ofp_ox_match *oxm; - uint8_t *p; - ssize_t len, mlen, plen; - off_t moff, off; - - off = 0; - if ((pin = ibuf_seek(ibuf, off, sizeof(*pin))) == NULL) - return (-1); - log_debug("\tbuffer %s length %u reason %s table %s cookie 0x%#016llx", - print_map(ntohl(pin->pin_buffer_id), ofp_pktout_map), - ntohs(pin->pin_total_len), - print_map(ntohs(pin->pin_reason), ofp_pktin_map), - print_map(pin->pin_table_id, ofp_table_id_map), - be64toh(pin->pin_cookie)); - off += offsetof(struct ofp_packet_in, pin_match); - - om = &pin->pin_match; - mlen = ntohs(om->om_length); - log_debug("\tmatch type %s length %zu (padded to %zu)", - print_map(ntohs(om->om_type), ofp_match_map), - mlen, OFP_ALIGN(mlen) + ETHER_ALIGN); - mlen -= sizeof(*om); - - /* current match offset, aligned offset after all matches */ - moff = off + sizeof(*om); - off += OFP_ALIGN(mlen) + ETHER_ALIGN; - - switch (htons(om->om_type)) { - case OFP_MATCH_OXM: - do { - if ((oxm = ibuf_seek(ibuf, moff, sizeof(*oxm))) == NULL) - return (-1); - if (ofp13_validate_oxm(sc, oxm, oh, ibuf, moff) == -1) - return (-1); - moff += sizeof(*oxm) + oxm->oxm_length; - mlen -= sizeof(*oxm) + oxm->oxm_length; - } while (mlen > 0 && oxm->oxm_length); - break; - case OFP_MATCH_STANDARD: - /* deprecated */ - break; - } - - len = ntohs(pin->pin_total_len); - plen = ibuf_length(ibuf) - off; - - if (plen < len) { - log_debug("\ttruncated packet %zu < %zu", plen, len); - - /* Buffered packets can be truncated */ - if (pin->pin_buffer_id != OFP_PKTOUT_NO_BUFFER) - len = plen; - else - return (-1); - } - if ((p = ibuf_seek(ibuf, off, len)) == NULL) - return (-1); - if (sc->sc_tap != -1) - (void)write(sc->sc_tap, p, len); - - return (0); -} - -int -ofp13_validate_packet_out(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_packet_out *pout; - size_t len, plen, diff; - off_t off, noff; - struct ofp_action_header *ah; - - off = 0; - if ((pout = ibuf_seek(ibuf, off, sizeof(*pout))) == NULL) { - log_debug("%s: seek failed: length %zd", - __func__, ibuf_length(ibuf)); - return (-1); - } - - off += sizeof(*pout); - len = ntohs(pout->pout_actions_len); - log_debug("\tbuffer %s in_port %s actions_len %lu", - print_map(ntohl(pout->pout_buffer_id), ofp_pktout_map), - print_map(ntohl(pout->pout_in_port), ofp_port_map), len); - - while (len > 0) { - if ((ah = ibuf_seek(ibuf, off, sizeof(*ah))) == NULL) - return (-1); - - noff = off; - ofp13_validate_action(sc, oh, ibuf, &off, ah); - - diff = off - noff; - /* Loop prevention. */ - if (off < noff || diff == 0) - return (-1); - - len -= diff; - } - - /* Check for encapsulated packet truncation. */ - len = ntohs(oh->oh_length) - off; - plen = ibuf_length(ibuf) - off; - - if (plen < len) { - log_debug("\ttruncated packet %lu < %lu", plen, len); - - /* Buffered packets can be truncated */ - if (pout->pout_buffer_id != htonl(OFP_PKTOUT_NO_BUFFER)) - len = plen; - else - return (-1); - } - if (ibuf_seek(ibuf, off, len) == NULL) - return (-1); - - return (0); -} - -int -ofp13_validate_error(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_error *err; - off_t off; - const char *code; - - off = 0; - if ((err = ibuf_seek(ibuf, off, sizeof(*err))) == NULL) { - log_debug("%s: seek failed: length %zd", - __func__, ibuf_length(ibuf)); - return (-1); - } - - switch (ntohs(err->err_type)) { - case OFP_ERRTYPE_FLOW_MOD_FAILED: - code = print_map(ntohs(err->err_code), ofp_errflowmod_map); - break; - case OFP_ERRTYPE_BAD_MATCH: - code = print_map(ntohs(err->err_code), ofp_errmatch_map); - break; - case OFP_ERRTYPE_BAD_INSTRUCTION: - code = print_map(ntohs(err->err_code), ofp_errinst_map); - break; - case OFP_ERRTYPE_BAD_REQUEST: - code = print_map(ntohs(err->err_code), ofp_errreq_map); - break; - default: - code = NULL; - break; - } - - log_debug("\terror type %s code %u%s%s", - print_map(ntohs(err->err_type), ofp_errtype_map), - ntohs(err->err_code), - code == NULL ? "" : ": ", - code == NULL ? "" : code); - - return (0); -} - -int -ofp13_input(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - if (ofp13_validate(sc, &con->con_peer, &con->con_local, oh, ibuf) != 0) - return (-1); - - if (ofp13_callbacks[oh->oh_type].cb == NULL) { - log_debug("%s: message not supported: %s", __func__, - print_map(oh->oh_type, ofp_t_map)); - return (-1); - } - if (ofp13_callbacks[oh->oh_type].cb(sc, con, oh, ibuf) != 0) { - log_debug("%s: message parsing failed: %s", __func__, - print_map(oh->oh_type, ofp_t_map)); - return (-1); - } - - return (0); -} - -int -ofp13_hello(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - if (switch_add(con) == NULL) { - log_debug("%s: failed to add switch", __func__); - return (-1); - } - - if (ofp_recv_hello(sc, con, oh, ibuf) == -1) - return (-1); - - return (ofp_nextstate(sc, con, OFP_STATE_FEATURE_WAIT)); -} - -int -ofp13_echo_request(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - /* Echo reply */ - oh->oh_type = OFP_T_ECHO_REPLY; - if (ofp13_validate(sc, &con->con_local, &con->con_peer, oh, NULL) != 0) - return (-1); - ofp_output(con, oh, NULL); - - return (0); -} - -int -ofp13_validate_features_reply(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_switch_features *swf; - - if ((swf = ibuf_seek(ibuf, 0, sizeof(*swf))) == NULL) - return (-1); - - log_debug("\tdatapath_id %#016llx nbuffers %u ntables %d aux_id %d " - "capabilities %#08x", - be64toh(swf->swf_datapath_id), ntohl(swf->swf_nbuffers), - swf->swf_ntables, swf->swf_aux_id, ntohl(swf->swf_capabilities)); - return (0); -} - -int -ofp13_features_reply(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - return (ofp_nextstate(sc, con, OFP_STATE_ESTABLISHED)); -} - -int -ofp13_validate_action(struct switchd *sc, struct ofp_header *oh, - struct ibuf *ibuf, off_t *off, struct ofp_action_header *ah) -{ - struct ofp_action_output *ao; - struct ofp_action_mpls_ttl *amt; - struct ofp_action_push *ap; - struct ofp_action_pop_mpls *apm; - struct ofp_action_group *ag; - struct ofp_action_nw_ttl *ant; - struct ofp_action_set_field *asf; - struct ofp_action_set_queue *asq; - struct ofp_ox_match *oxm; - size_t len; - int type; - off_t moff; - - type = ntohs(ah->ah_type); - len = ntohs(ah->ah_len); - - switch (type) { - case OFP_ACTION_OUTPUT: - if (len != sizeof(*ao)) - return (-1); - if ((ao = ibuf_seek(ibuf, *off, sizeof(*ao))) == NULL) - return (-1); - - *off += len; - log_debug("\t\taction %s len %lu port %s max_len %s", - print_map(type, ofp_action_map), len, - print_map(ntohl(ao->ao_port), ofp_port_map), - print_map(ntohs(ao->ao_max_len), - ofp_controller_maxlen_map)); - break; - case OFP_ACTION_SET_MPLS_TTL: - if (len != sizeof(*amt)) - return (-1); - if ((amt = ibuf_seek(ibuf, *off, sizeof(*amt))) == NULL) - return (-1); - - *off += len; - log_debug("\t\taction %s len %lu ttl %d", - print_map(type, ofp_action_map), len, amt->amt_ttl); - break; - case OFP_ACTION_PUSH_VLAN: - case OFP_ACTION_PUSH_MPLS: - case OFP_ACTION_PUSH_PBB: - if (len != sizeof(*ap)) - return (-1); - if ((ap = ibuf_seek(ibuf, *off, sizeof(*ap))) == NULL) - return (-1); - - *off += len; - log_debug("\t\taction %s len %lu ethertype %#04x", - print_map(type, ofp_action_map), len, - ntohs(ap->ap_ethertype)); - break; - case OFP_ACTION_POP_MPLS: - if (len != sizeof(*apm)) - return (-1); - if ((apm = ibuf_seek(ibuf, *off, sizeof(*apm))) == NULL) - return (-1); - - *off += len; - log_debug("\t\taction %s len %lu ethertype %#04x", - print_map(type, ofp_action_map), len, - ntohs(apm->apm_ethertype)); - break; - case OFP_ACTION_SET_QUEUE: - if (len != sizeof(*asq)) - return (-1); - if ((asq = ibuf_seek(ibuf, *off, sizeof(*asq))) == NULL) - return (-1); - - *off += len; - log_debug("\t\taction %s len %lu queue_id %u", - print_map(type, ofp_action_map), len, - ntohl(asq->asq_queue_id)); - break; - case OFP_ACTION_GROUP: - if (len != sizeof(*ag)) - return (-1); - if ((ag = ibuf_seek(ibuf, *off, sizeof(*ag))) == NULL) - return (-1); - - *off += len; - log_debug("\t\taction %s len %lu group_id %s", - print_map(type, ofp_action_map), len, - print_map(ntohl(ag->ag_group_id), ofp_group_id_map)); - break; - case OFP_ACTION_SET_NW_TTL: - if (len != sizeof(*ant)) - return (-1); - if ((ant = ibuf_seek(ibuf, *off, sizeof(*ant))) == NULL) - return (-1); - - *off += len; - log_debug("\t\taction %s len %lu ttl %d", - print_map(type, ofp_action_map), len, ant->ant_ttl); - break; - case OFP_ACTION_SET_FIELD: - if (len < sizeof(*asf) || len != OFP_ALIGN(len)) - return (-1); - if ((asf = ibuf_seek(ibuf, *off, sizeof(*asf))) == NULL) - return (-1); - - moff = *off + sizeof(*asf) - sizeof(asf->asf_field); - *off += len; - log_debug("\t\taction %s len %lu", - print_map(type, ofp_action_map), len); - - len -= sizeof(*asf) - sizeof(asf->asf_field); - if ((oxm = ibuf_seek(ibuf, moff, sizeof(*oxm))) == NULL) - return (-1); - if (ofp13_validate_oxm(sc, oxm, oh, ibuf, moff) == -1) - return (-1); - - len -= sizeof(*oxm) + oxm->oxm_length; - if (len >= OFP_ALIGNMENT) - return (-1); - break; - - default: - if (len < sizeof(*ah)) - return (-1); - - /* Generic header without information. */ - *off += len; - log_debug("\t\taction %s len %lu", - print_map(type, ofp_action_map), len); - break; - } - - return (0); -} - -int -ofp13_validate_instruction(struct switchd *sc, struct ofp_header *oh, - struct ibuf *ibuf, off_t *off, struct ofp_instruction *i) -{ - struct ofp_instruction_actions *ia; - struct ofp_instruction_goto_table *igt; - struct ofp_instruction_write_metadata *iwm; - struct ofp_instruction_meter *im; - struct ofp_action_header *ah; - int type; - size_t len; - off_t oldoff, diff; - - type = ntohs(i->i_type); - len = ntohs(i->i_len); - - switch (type) { - case OFP_INSTRUCTION_T_GOTO_TABLE: - if (len != sizeof(*igt)) - return (-1); - if ((igt = ibuf_seek(ibuf, *off, sizeof(*igt))) == NULL) - return (-1); - - *off += len; - log_debug("\tinstruction %s length %lu table_id %s", - print_map(type, ofp_instruction_t_map), len, - print_map(igt->igt_table_id, ofp_table_id_map)); - break; - case OFP_INSTRUCTION_T_WRITE_META: - if (len != sizeof(*iwm)) - return (-1); - if ((iwm = ibuf_seek(ibuf, *off, sizeof(*iwm))) == NULL) - return (-1); - - *off += len; - log_debug("\tinstruction %s length %lu " - "metadata %#016llx mask %#016llx", - print_map(type, ofp_instruction_t_map), len, - be64toh(iwm->iwm_metadata), - be64toh(iwm->iwm_metadata_mask)); - break; - case OFP_INSTRUCTION_T_METER: - if (len != sizeof(*im)) - return (-1); - if ((im = ibuf_seek(ibuf, *off, sizeof(*im))) == NULL) - return (-1); - - *off += len; - log_debug("\tinstruction %s length %lu meter_id %d", - print_map(type, ofp_instruction_t_map), len, - im->im_meter_id); - break; - case OFP_INSTRUCTION_T_WRITE_ACTIONS: - case OFP_INSTRUCTION_T_CLEAR_ACTIONS: - case OFP_INSTRUCTION_T_APPLY_ACTIONS: - if (len < sizeof(*ia)) - return (-1); - if ((ia = ibuf_seek(ibuf, *off, sizeof(*ia))) == NULL) - return (-1); - - log_debug("\tinstruction %s length %lu", - print_map(type, ofp_instruction_t_map), len); - - *off += sizeof(*ia); - len -= sizeof(*ia); - while (len) { - oldoff = *off; - if ((ah = ibuf_seek(ibuf, *off, sizeof(*ah))) == NULL || - ofp13_validate_action(sc, oh, ibuf, off, ah) == -1) - return (-1); - - diff = *off - oldoff; - /* Loop prevention. */ - if (*off < oldoff || diff == 0) - break; - - len -= diff; - } - break; - default: - if (len < sizeof(*i)) - return (-1); - - log_debug("\tinstruction %s length %lu", - print_map(type, ofp_instruction_t_map), len); - *off += len; - break; - } - - return (0); -} - -int -ofp13_validate_flow_mod(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_flow_mod *fm; - struct ofp_match *om; - struct ofp_instruction *i; - struct ofp_ox_match *oxm; - off_t off, moff, offdiff; - int matchlen, matchtype, left; - - off = 0; - if ((fm = ibuf_seek(ibuf, off, sizeof(*fm))) == NULL) - return (-1); - - log_debug("\tcommand %s table %s timeout (idle %d hard %d) " - "priority %d buffer_id %s out_port %s out_group %s " - "flags %#04x cookie %#016llx mask %#016llx", - print_map(fm->fm_command, ofp_flowcmd_map), - print_map(fm->fm_table_id, ofp_table_id_map), - ntohs(fm->fm_idle_timeout), ntohs(fm->fm_hard_timeout), - ntohs(fm->fm_priority), - print_map(ntohl(fm->fm_buffer_id), ofp_pktout_map), - print_map(ntohl(fm->fm_out_port), ofp_port_map), - print_map(ntohl(fm->fm_out_group), ofp_group_id_map), - ntohs(fm->fm_flags), be64toh(fm->fm_cookie), - be64toh(fm->fm_cookie_mask)); - - off += offsetof(struct ofp_flow_mod, fm_match); - - om = &fm->fm_match; - matchtype = ntohs(om->om_type); - matchlen = ntohs(om->om_length); - - moff = off + sizeof(*om); - off += OFP_ALIGN(matchlen); - - matchlen -= sizeof(*om); - while (matchlen) { - if ((oxm = ibuf_seek(ibuf, moff, sizeof(*oxm))) == NULL || - ofp13_validate_oxm(sc, oxm, oh, ibuf, moff) == -1) - return (-1); - moff += sizeof(*oxm) + oxm->oxm_length; - matchlen -= sizeof(*oxm) + oxm->oxm_length; - } - - left = ntohs(oh->oh_length) - off; - moff = off; - while (left) { - if ((i = ibuf_seek(ibuf, moff, sizeof(*i))) == NULL || - ofp13_validate_instruction(sc, oh, ibuf, &moff, i) == -1) - return (-1); - - offdiff = moff - off; - /* Loop prevention. */ - if (moff < off || offdiff == 0) - break; - - left -= offdiff; - off = moff; - } - - return (0); -} - -int -ofp13_packet_match(struct ibuf *ibuf, struct packet *pkt, struct ofp_match *om) -{ - struct ether_header *eh = pkt->pkt_eh; - size_t padsize, startpos, endpos, omlen; - - if (eh == NULL) - return (-1); - - startpos = ibuf->wpos; - if (oxm_etheraddr(ibuf, 1, eh->ether_shost, NULL) == -1) - return (-1); - if (oxm_etheraddr(ibuf, 0, eh->ether_dhost, NULL) == -1) - return (-1); - endpos = ibuf->wpos; - - omlen = sizeof(*om) + (endpos - startpos); - padsize = OFP_ALIGN(omlen) - omlen; - - om->om_type = htons(OFP_MATCH_OXM); - om->om_length = htons(omlen); - if (padsize && ibuf_advance(ibuf, padsize) == NULL) - return (-1); - - return (0); -} - -int -ofp13_packet_in(struct switchd *sc, struct switch_connection *con, - struct ofp_header *ih, struct ibuf *ibuf) -{ - struct ofp_packet_in *pin; - struct ofp_packet_out *pout; - struct ofp_flow_mod *fm; - struct ofp_header *oh; - struct ofp_match *om; - struct ofp_ox_match *oxm; - struct packet pkt; - struct ibuf *obuf = NULL; - int table, ret = -1; - ssize_t len, mlen; - uint32_t srcport = 0, dstport; - int addflow = 0, sendbuffer = 0; - off_t off, moff; - void *ptr; - struct ofp_instruction_actions *ia; - - if ((pin = ibuf_getdata(ibuf, sizeof(*pin))) == NULL) - return (-1); - - /* We only handle no matches right now. */ - if (pin->pin_reason != OFP_PKTIN_REASON_NO_MATCH) - return (-1); - - memset(&pkt, 0, sizeof(pkt)); - len = ntohs(pin->pin_total_len); - - /* very basic way of getting the source port */ - om = &pin->pin_match; - mlen = ntohs(om->om_length); - off = (OFP_ALIGN(mlen) + ETHER_ALIGN) - sizeof(pin->pin_match); - moff = ibuf_dataoffset(ibuf); - - do { - if ((oxm = ibuf_seek(ibuf, moff, sizeof(*oxm))) == NULL) - return (-1); - - /* Find IN_PORT */ - switch (ntohs(oxm->oxm_class)) { - case OFP_OXM_C_OPENFLOW_BASIC: - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_IN_PORT: - moff += sizeof(*oxm); - if ((ptr = ibuf_seek(ibuf, moff, - sizeof(srcport))) == NULL) - return (-1); - srcport = htonl(*(uint32_t *)ptr); - mlen = 0; /* break loop */ - break; - default: - /* ignore unsupported match types */ - break; - } - default: - /* ignore unsupported match classes */ - break; - } - moff += sizeof(*oxm) + oxm->oxm_length; - mlen -= sizeof(*oxm) + oxm->oxm_length; - } while (mlen > 0 && oxm->oxm_length); - - /* Skip all matches and seek to the packet */ - if (ibuf_getdata(ibuf, off) == NULL) - return (-1); - - if (packet_ether_input(ibuf, len, &pkt) == -1 && - pin->pin_buffer_id == htonl(OFP_PKTOUT_NO_BUFFER)) - return(-1); - - if (packet_input(sc, con->con_switch, - srcport, &dstport, &pkt) == -1 || - (dstport > OFP_PORT_MAX && - dstport != OFP_PORT_LOCAL && - dstport != OFP_PORT_CONTROLLER)) { - /* fallback to flooding */ - dstport = OFP_PORT_FLOOD; - } else if (srcport == dstport) { - /* - * silently drop looping packet - * (don't use OFP_PORT_INPUT here) - */ - ret = 0; - goto done; - } else { - addflow = 1; - } - - if ((obuf = ibuf_static()) == NULL) - goto done; - - again: - if (addflow) { - table = ofp13_getflowtable(con); - if (table > OFP_TABLE_ID_MAX || table < 0) { - /* This switch doesn't support installing flows. */ - addflow = 0; - goto again; - } - - if ((fm = ibuf_advance(obuf, sizeof(*fm))) == NULL) - goto done; - - oh = &fm->fm_oh; - fm->fm_cookie = 0; /* XXX should we set a cookie? */ - fm->fm_command = OFP_FLOWCMD_ADD; - fm->fm_idle_timeout = htons(sc->sc_cache_timeout); - fm->fm_hard_timeout = 0; /* permanent */ - fm->fm_priority = 0; - fm->fm_buffer_id = pin->pin_buffer_id; - fm->fm_table_id = table; - fm->fm_flags = htons(OFP_FLOWFLAG_SEND_FLOW_REMOVED); - if (pin->pin_buffer_id == htonl(OFP_PKTOUT_NO_BUFFER)) - sendbuffer = 1; - - /* Write flow matches to create an entry. */ - if (ofp13_packet_match(obuf, &pkt, &fm->fm_match) == -1) - goto done; - - /* - * Write the instruction action header and add the output - * action. - */ - if ((ia = ibuf_advance(obuf, sizeof(*ia))) == NULL || - action_output(obuf, dstport, - OFP_CONTROLLER_MAXLEN_NO_BUFFER) == -1) - goto done; - - ia->ia_type = htons(OFP_INSTRUCTION_T_APPLY_ACTIONS); - ia->ia_len = htons(sizeof(*ia) + - sizeof(struct ofp_action_output)); - } else { - if ((pout = ibuf_advance(obuf, sizeof(*pout))) == NULL) - goto done; - - oh = &pout->pout_oh; - pout->pout_buffer_id = pin->pin_buffer_id; - pout->pout_in_port = htonl(srcport); - pout->pout_actions_len = - htons(sizeof(struct ofp_action_output)); - - if (action_output(obuf, dstport, - OFP_CONTROLLER_MAXLEN_NO_BUFFER) == -1) - goto done; - - /* Add optional packet payload */ - if (pin->pin_buffer_id == htonl(OFP_PKTOUT_NO_BUFFER) && - imsg_add(obuf, pkt.pkt_buf, pkt.pkt_len) == -1) - goto done; - } - - /* Set output header */ - oh->oh_version = OFP_V_1_3; - oh->oh_length = htons(ibuf_length(obuf)); - oh->oh_type = addflow ? OFP_T_FLOW_MOD : OFP_T_PACKET_OUT; - oh->oh_xid = htonl(con->con_xidnxt++); - - if (ofp13_validate(sc, &con->con_local, &con->con_peer, oh, obuf) != 0) - goto done; - - ofp_output(con, NULL, obuf); - - if (sendbuffer) { - ibuf_release(obuf); - - /* loop to output the packet again */ - addflow = sendbuffer = 0; - if ((obuf = ibuf_static()) == NULL) - goto done; - goto again; - } - - ret = 0; - done: - ibuf_release(obuf); - return (ret); -} - -int -ofp13_flow_removed(struct switchd *sc, struct switch_connection *con, - struct ofp_header *ih, struct ibuf *ibuf) -{ - struct ofp_flow_removed *fr; - - if ((fr = ibuf_getdata(ibuf, sizeof(*fr))) == NULL) - return (-1); - - log_debug("cookie %#016llx priority %d reason %s table_id %s " - "duration(%u sec, %u nsec) timeout idle %d hard %d " - "packet %llu byte %llu", - be64toh(fr->fr_cookie), ntohs(fr->fr_priority), - print_map(fr->fr_reason, ofp_flowrem_reason_map), - print_map(fr->fr_table_id, ofp_table_id_map), - ntohl(fr->fr_duration_sec), ntohl(fr->fr_duration_nsec), - ntohs(fr->fr_idle_timeout), ntohs(fr->fr_hard_timeout), - be64toh(fr->fr_packet_count), be64toh(fr->fr_byte_count)); - - return (0); -} - -int -ofp13_tableproperties(struct switch_connection *con, struct ibuf *ibuf, - off_t off, size_t total, int new) -{ - struct ofp_table_features *tf; - struct ofp_table_feature_property *tp; - struct ofp_instruction *i; - struct ofp_action_header *ah; - struct ofp_ox_match *oxm; - struct switch_table *st; - uint8_t *next_table; - int remaining, type, length; - int hlen, padsize; - int class, dtype, dlen; - - /* - * This is a new table features reply, free our previous tables - * to get the updated ones. - */ - if (new) - switch_freetables(con); - - next_table: - if ((tf = ibuf_seek(ibuf, off, sizeof(*tf))) == NULL) - return (-1); - - hlen = htons(tf->tf_length); - total -= hlen; - remaining = hlen - sizeof(*tf); - off += sizeof(*tf); - - st = switch_tablelookup(con, tf->tf_tableid); - if (st == NULL) { - st = switch_newtable(con, tf->tf_tableid); - if (st == NULL) - return (-1); - } - - st->st_maxentries = ntohl(tf->tf_max_entries); - - next_table_property: - if ((tp = ibuf_seek(ibuf, off, sizeof(*tp))) == NULL) { - switch_deltable(con, st); - return (-1); - } - - type = ntohs(tp->tp_type); - length = ntohs(tp->tp_length); - - /* Calculate the padding. */ - padsize = OFP_ALIGN(length) - length; - remaining -= OFP_ALIGN(length); - length -= sizeof(*tp); - off += sizeof(*tp); - - switch (type) { - case OFP_TABLE_FEATPROP_INSTRUCTION: - case OFP_TABLE_FEATPROP_INSTRUCTION_MISS: - if (type == OFP_TABLE_FEATPROP_INSTRUCTION) - st->st_instructions = 0; - else - st->st_instructionsmiss = 0; - - while (length) { - if ((i = ibuf_seek(ibuf, off, sizeof(*i))) == NULL) { - switch_deltable(con, st); - return (-1); - } - - dtype = ntohs(i->i_type); - dlen = ntohs(i->i_len); - if (type == OFP_TABLE_FEATPROP_INSTRUCTION) - st->st_instructions |= 1ULL << dtype; - else - st->st_instructionsmiss |= 1ULL << dtype; - - if (dtype == OFP_INSTRUCTION_T_EXPERIMENTER) { - length -= dlen; - off += dlen; - } else { - length -= sizeof(*i); - off += sizeof(*i); - } - } - break; - - case OFP_TABLE_FEATPROP_NEXT_TABLES: - case OFP_TABLE_FEATPROP_NEXT_TABLES_MISS: - if (type == OFP_TABLE_FEATPROP_NEXT_TABLES) - memset(st->st_nexttable, 0, sizeof(st->st_nexttable)); - else - memset(st->st_nexttablemiss, 0, - sizeof(st->st_nexttablemiss)); - - while (length) { - if ((next_table = ibuf_seek(ibuf, off, - sizeof(*next_table))) == NULL) { - switch_deltable(con, st); - return (-1); - } - - if (type == OFP_TABLE_FEATPROP_NEXT_TABLES) - st->st_nexttable[(*next_table) / 64] |= - 1ULL << ((*next_table) % 64); - else - st->st_nexttablemiss[(*next_table) / 64] |= - 1ULL << ((*next_table) % 64); - - length -= sizeof(*next_table); - off += sizeof(*next_table); - } - break; - - case OFP_TABLE_FEATPROP_WRITE_ACTIONS: - case OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS: - case OFP_TABLE_FEATPROP_APPLY_ACTIONS: - case OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS: - if (type == OFP_TABLE_FEATPROP_WRITE_ACTIONS || - type == OFP_TABLE_FEATPROP_APPLY_ACTIONS) - st->st_actions = 0; - else - st->st_actionsmiss = 0; - - while (length) { - /* - * NOTE the OpenFlow 1.3.5 specs says that we only - * get 4 bytes here instead of the full action header. - */ - if ((ah = ibuf_seek(ibuf, off, 4)) == NULL) { - switch_deltable(con, st); - return (-1); - } - - dtype = ntohs(ah->ah_type); - dlen = ntohs(ah->ah_len); - if (type == OFP_TABLE_FEATPROP_WRITE_ACTIONS || - type == OFP_TABLE_FEATPROP_APPLY_ACTIONS) - st->st_actions |= 1ULL << dtype; - else - st->st_actionsmiss |= 1ULL << dtype; - - if (dtype == OFP_ACTION_EXPERIMENTER) { - length -= dlen; - off += dlen; - } else { - length -= 4; - off += 4; - } - } - break; - - case OFP_TABLE_FEATPROP_MATCH: - case OFP_TABLE_FEATPROP_WILDCARDS: - case OFP_TABLE_FEATPROP_WRITE_SETFIELD: - case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS: - case OFP_TABLE_FEATPROP_APPLY_SETFIELD: - case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS: - if (type == OFP_TABLE_FEATPROP_WRITE_SETFIELD || - type == OFP_TABLE_FEATPROP_APPLY_SETFIELD) - st->st_setfield = 0; - else if (type == OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS || - type == OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS) - st->st_setfieldmiss = 0; - else if (type == OFP_TABLE_FEATPROP_MATCH) - st->st_match = 0; - else - st->st_wildcard = 0; - - while (length) { - if ((oxm = ibuf_seek(ibuf, off, - sizeof(*oxm))) == NULL) { - switch_deltable(con, st); - return (-1); - } - - class = ntohs(oxm->oxm_class); - if (class != OFP_OXM_C_OPENFLOW_BASIC) { - if (class == OFP_OXM_C_OPENFLOW_EXPERIMENTER) { - length -= sizeof(*oxm) + 4; - off += sizeof(*oxm) + 4; - } else { - length -= sizeof(*oxm); - off += sizeof(*oxm); - } - continue; - } - - dtype = OFP_OXM_GET_FIELD(oxm); - if (type == OFP_TABLE_FEATPROP_WRITE_SETFIELD || - type == OFP_TABLE_FEATPROP_APPLY_SETFIELD) - st->st_setfield |= 1ULL << dtype; - else if - (type == OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS || - type == OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS) - st->st_setfieldmiss |= 1ULL << dtype; - else if (type == OFP_TABLE_FEATPROP_MATCH) - st->st_match |= 1ULL << dtype; - else - st->st_wildcard |= 1ULL << dtype; - - length -= sizeof(*oxm); - off += sizeof(*oxm); - } - break; - - case OFP_TABLE_FEATPROP_EXPERIMENTER: - case OFP_TABLE_FEATPROP_EXPERIMENTER_MISS: - off += length; - break; - - default: - log_debug("Unsupported table property %d", type); - return (-1); - } - - if (padsize) - off += padsize; - if (remaining > 0) - goto next_table_property; - if (total > 0) - goto next_table; - - return (0); -} - -int -ofp13_multipart_reply(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_multipart *mp; - int type, flags, more, new = 0; - int remaining; - off_t off; - - off = 0; - if ((mp = ibuf_seek(ibuf, 0, sizeof(*mp))) == NULL) - return (-1); - - type = ntohs(mp->mp_type); - flags = ntohs(mp->mp_flags); - remaining = ntohs(oh->oh_length) - sizeof(*mp); - off += sizeof(*mp); - - more = (flags & OFP_MP_FLAG_REPLY_MORE) == OFP_MP_FLAG_REPLY_MORE; - /* Signalize new requests. */ - if (ofp_multipart_lookup(con, oh->oh_xid) == NULL) - new = 1; - - if (more) { - if (ofp_multipart_add(con, oh->oh_xid, type) == -1) { - ofp13_error(sc, con, oh, ibuf, - OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_MULTIPART_OVERFLOW); - ofp_multipart_del(con, oh->oh_xid); - return (0); - } - - /* - * We don't need to concatenate with other messages, - * because the specification says that switches don't - * break objects. We should only need this if our parser - * requires the whole data before hand, but then we have - * better ways to achieve the same thing. - */ - } else - ofp_multipart_del(con, oh->oh_xid); - - switch (type) { - case OFP_MP_T_TABLE_FEATURES: - if (ofp13_tableproperties(con, ibuf, off, remaining, new)) - return (-1); - - /* We finished receiving tables, configure the switch. */ - if (more == 0) - return (ofp13_switchconfigure(sc, con)); - break; - } - - return (0); -} - -int -ofp13_validate_tableproperty(struct ibuf *ibuf, off_t off, int remaining) -{ - struct ofp_table_features *tf; - struct ofp_table_feature_property *tp; - struct ofp_instruction *i; - struct ofp_action_header *ah; - struct ofp_ox_match *oxm; - uint8_t *nexttable; - int hlen, htype, tplen; - int type, length, class; - int padsize; - - next_table: - if ((tf = ibuf_seek(ibuf, off, sizeof(*tf))) == NULL) - return (-1); - - hlen = ntohs(tf->tf_length); - log_debug("\t\ttable features length %d tableid %s " - " name \"%s\" metadata match %#016llx write %#016llx " - "config %u max_entries %u", - hlen, print_map(tf->tf_tableid, ofp_table_id_map), tf->tf_name, - be64toh(tf->tf_metadata_match), - be64toh(tf->tf_metadata_write), ntohl(tf->tf_config), - ntohl(tf->tf_max_entries)); - - off += sizeof(*tf); - remaining -= sizeof(*tf); - hlen -= sizeof(*tf); - - next_property: - if ((tp = ibuf_seek(ibuf, off, sizeof(*tp))) == NULL) - return (-1); - - off += sizeof(*tp); - htype = ntohs(tp->tp_type); - tplen = ntohs(tp->tp_length); - padsize = OFP_ALIGN(tplen) - tplen; - remaining -= tplen; - hlen -= tplen; - - /* Don't count the header bytes for payload. */ - tplen -= sizeof(*tp); - - log_debug("\t\t%s (length %d):", - print_map(htype, ofp_table_featprop_map), tplen); - if (tplen <= 0) - goto empty_table; - - switch (htype) { - case OFP_TABLE_FEATPROP_INSTRUCTION: - case OFP_TABLE_FEATPROP_INSTRUCTION_MISS: - while (tplen > 0) { - if ((i = ibuf_seek(ibuf, off, sizeof(*i))) == NULL) - return (-1); - - type = ntohs(i->i_type); - length = ntohs(i->i_len); - if (type == OFP_INSTRUCTION_T_EXPERIMENTER) { - tplen -= length; - off += length; - } else { - tplen -= sizeof(*i); - off += sizeof(*i); - } - - log_debug("\t\t\ttype %s length %d", - print_map(type, ofp_instruction_t_map), length); - } - break; - - case OFP_TABLE_FEATPROP_NEXT_TABLES: - case OFP_TABLE_FEATPROP_NEXT_TABLES_MISS: - while (tplen > 0) { - if ((nexttable = ibuf_seek(ibuf, off, - sizeof(*nexttable))) == NULL) - return (-1); - - log_debug("\t\t\t%d", *nexttable); - - off += sizeof(*nexttable); - tplen -= sizeof(*nexttable); - } - break; - - case OFP_TABLE_FEATPROP_WRITE_ACTIONS: - case OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS: - case OFP_TABLE_FEATPROP_APPLY_ACTIONS: - case OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS: - while (tplen > 0) { - /* NOTE: we read the action header without the pad. */ - if ((ah = ibuf_seek(ibuf, off, 4)) == NULL) - return (-1); - - type = ntohs(ah->ah_type); - length = ntohs(ah->ah_len); - log_debug("\t\t\taction %s length %d", - print_map(type, ofp_action_map), length); - if (type == OFP_ACTION_EXPERIMENTER) { - tplen -= length; - off += length; - } else { - tplen -= 4; - off += 4; - } - } - break; - - case OFP_TABLE_FEATPROP_MATCH: - case OFP_TABLE_FEATPROP_WILDCARDS: - case OFP_TABLE_FEATPROP_WRITE_SETFIELD: - case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS: - case OFP_TABLE_FEATPROP_APPLY_SETFIELD: - case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS: - while (tplen > 0) { - if ((oxm = ibuf_seek(ibuf, off, sizeof(*oxm))) == NULL) - return (-1); - - class = ntohs(oxm->oxm_class); - type = OFP_OXM_GET_FIELD(oxm); - length = oxm->oxm_length; - if (class == OFP_OXM_C_OPENFLOW_EXPERIMENTER) { - off += sizeof(*oxm) + 4; - tplen -= sizeof(*oxm) + 4; - } else { - off += sizeof(*oxm); - tplen -= sizeof(*oxm); - } - - log_debug("\t\t\tclass %s type %s length %d", - print_map(class, ofp_oxm_c_map), - print_map(type, ofp_xm_t_map), length); - } - break; - - case OFP_TABLE_FEATPROP_EXPERIMENTER: - case OFP_TABLE_FEATPROP_EXPERIMENTER_MISS: - off += tplen; - break; - - default: - return (-1); - } - - empty_table: - if (padsize) { - off += padsize; - remaining -= padsize; - hlen -= padsize; - } - if (hlen > 0) - goto next_property; - if (remaining > 0) - goto next_table; - - return (0); -} - -int -ofp13_multipart_reply_validate(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_multipart *mp; - struct ofp_flow_stats *fs; - struct ofp_desc *d; - struct ofp_match *om; - struct ofp_ox_match *oxm; - struct ofp_instruction *oi; - int mptype, mpflags, hlen; - int remaining, matchlen, matchtype; - int ilen, padsize; - off_t off, moff, offdiff; - - remaining = ntohs(oh->oh_length); - - off = 0; - if ((mp = ibuf_seek(ibuf, off, sizeof(*mp))) == NULL) - return (-1); - - mptype = ntohs(mp->mp_type); - mpflags = ntohs(mp->mp_flags); - log_debug("\ttype %s flags %#04x", - print_map(mptype, ofp_mp_t_map), mpflags); - - off += sizeof(*mp); - remaining -= sizeof(*mp); - if (remaining == 0) { - log_debug("\tempty reply"); - return (0); - } - - switch (mptype) { - case OFP_MP_T_DESC: - if ((d = ibuf_seek(ibuf, off, sizeof(*d))) == NULL) - return (-1); - - off += sizeof(*d); - remaining -= sizeof(*d); - log_debug("\tmfr_desc \"%s\" hw_desc \"%s\" sw_desc \"%s\" " - "serial_num \"%s\" dp_desc \"%s\"", - d->d_mfr_desc, d->d_hw_desc, d->d_sw_desc, - d->d_serial_num, d->d_dp_desc); - break; - - case OFP_MP_T_FLOW: - read_next_flow: - if ((fs = ibuf_seek(ibuf, off, sizeof(*fs))) == NULL) - return (-1); - - hlen = ntohs(fs->fs_length); - remaining -= hlen; - moff = off + sizeof(*fs); - off += hlen; - - log_debug("\tflow length %d table_id %s duration sec %u " - "nsec %u prio %d timeout idle %d hard %d flags %#04x " - "cookie %#016llx packet count %llu byte count %llu", - hlen, print_map(fs->fs_table_id, ofp_table_id_map), - ntohl(fs->fs_duration_sec), ntohl(fs->fs_duration_nsec), - ntohs(fs->fs_priority), ntohs(fs->fs_idle_timeout), - ntohs(fs->fs_hard_timeout), ntohs(fs->fs_flags), - be64toh(fs->fs_cookie), be64toh(fs->fs_packet_count), - be64toh(fs->fs_byte_count)); - - om = &fs->fs_match; - matchtype = ntohs(om->om_type); - matchlen = ntohs(om->om_length); - padsize = OFP_ALIGN(matchlen) - matchlen; - ilen = hlen - - ((sizeof(*fs) - sizeof(*om)) + matchlen + padsize); - - /* We don't know how to parse anything else yet. */ - if (matchtype != OFP_MATCH_OXM) - break; - - matchlen -= sizeof(*om); - while (matchlen) { - if ((oxm = ibuf_seek(ibuf, moff, sizeof(*oxm))) == NULL) - return (-1); - if (ofp13_validate_oxm(sc, oxm, oh, ibuf, moff) == -1) - return (-1); - moff += sizeof(*oxm) + oxm->oxm_length; - matchlen -= sizeof(*oxm) + oxm->oxm_length; - } - - moff += padsize; - - while (ilen) { - offdiff = moff; - if ((oi = ibuf_seek(ibuf, moff, sizeof(*oi))) == NULL || - ofp13_validate_instruction(sc, oh, ibuf, - &moff, oi) == -1) - return (-1); - /* Avoid loops. */ - if ((moff - offdiff) == 0) - return (-1); - - ilen -= moff - offdiff; - } - - if (remaining) - goto read_next_flow; - break; - - case OFP_MP_T_AGGREGATE: - case OFP_MP_T_TABLE: - case OFP_MP_T_PORT_STATS: - case OFP_MP_T_QUEUE: - case OFP_MP_T_GROUP: - case OFP_MP_T_GROUP_DESC: - case OFP_MP_T_GROUP_FEATURES: - case OFP_MP_T_METER: - case OFP_MP_T_METER_CONFIG: - case OFP_MP_T_METER_FEATURES: - break; - - case OFP_MP_T_TABLE_FEATURES: - if (ofp13_validate_tableproperty(ibuf, off, remaining)) - return (-1); - break; - - case OFP_MP_T_PORT_DESC: - case OFP_MP_T_EXPERIMENTER: - break; - - default: - return (-1); - } - - return (0); -} - -/* Don't forget to update mp->mp_oh.oh_length */ -struct ofp_multipart * -ofp13_multipart_request(struct switch_connection *con, struct ibuf *ibuf, - uint16_t type, uint16_t flags) -{ - struct ofp_multipart *mp; - struct ofp_header *oh; - - if ((mp = ibuf_advance(ibuf, sizeof(*mp))) == NULL) - return (NULL); - - oh = &mp->mp_oh; - oh->oh_version = OFP_V_1_3; - oh->oh_type = OFP_T_MULTIPART_REQUEST; - oh->oh_xid = htonl(con->con_xidnxt++); - mp->mp_type = htons(type); - mp->mp_flags = htons(flags); - return (mp); -} - -int -ofp13_multipart_request_validate(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_multipart *mp; - struct ofp_match *om; - struct ofp_flow_stats_request *fsr; - struct ofp_ox_match *oxm; - off_t off, moff; - int type, flags, totallen; - int matchlen, matchtype; - - off = 0; - if ((mp = ibuf_seek(ibuf, off, sizeof(*mp))) == NULL) - return (-1); - - type = ntohs(mp->mp_type); - flags = ntohs(mp->mp_flags); - log_debug("\ttype %s flags %#04x", - print_map(type, ofp_mp_t_map), flags); - - totallen = ntohs(oh->oh_length); - off += sizeof(*mp); - - switch (type) { - case OFP_MP_T_DESC: - /* This type doesn't use a payload. */ - if (totallen != sizeof(*mp)) - return (-1); - break; - - case OFP_MP_T_FLOW: - if ((fsr = ibuf_seek(ibuf, off, sizeof(*fsr))) == NULL) - return (-1); - - om = &fsr->fsr_match; - matchtype = ntohs(om->om_type); - matchlen = ntohs(om->om_length); - log_debug("\ttable_id %s out_port %s out_group %s " - "cookie %#016llx mask %#016llx match type %s length %d " - "(padded to %d)", - print_map(fsr->fsr_table_id, ofp_table_id_map), - print_map(ntohl(fsr->fsr_out_port), ofp_port_map), - print_map(ntohl(fsr->fsr_out_group), ofp_group_id_map), - be64toh(fsr->fsr_cookie), be64toh(fsr->fsr_cookie_mask), - print_map(matchtype, ofp_match_map), matchlen, - OFP_ALIGN(matchlen)); - - /* Get the first OXM byte offset. */ - moff = off + sizeof(*fsr); - - /* Don't count the header bytes. */ - matchlen -= sizeof(*om); - - /* We don't know how to parse anything else yet. */ - if (matchtype != OFP_MATCH_OXM) - break; - - while (matchlen) { - if ((oxm = ibuf_seek(ibuf, moff, sizeof(*oxm))) == NULL) - return (-1); - if (ofp13_validate_oxm(sc, oxm, oh, ibuf, moff) == -1) - return (-1); - moff += sizeof(*oxm) + oxm->oxm_length; - matchlen -= sizeof(*oxm) + oxm->oxm_length; - } - break; - - case OFP_MP_T_AGGREGATE: - case OFP_MP_T_TABLE: - case OFP_MP_T_PORT_STATS: - case OFP_MP_T_QUEUE: - case OFP_MP_T_GROUP: - case OFP_MP_T_GROUP_DESC: - case OFP_MP_T_GROUP_FEATURES: - case OFP_MP_T_METER: - case OFP_MP_T_METER_CONFIG: - case OFP_MP_T_METER_FEATURES: - break; - - case OFP_MP_T_TABLE_FEATURES: - if (totallen == sizeof(*mp)) { - log_debug("\tempty table properties request"); - break; - } - break; - - case OFP_MP_T_PORT_DESC: - case OFP_MP_T_EXPERIMENTER: - break; - - default: - return (-1); - } - - return (0); -} - -int -ofp13_desc(struct switchd *sc, struct switch_connection *con) -{ - struct ofp_header *oh; - struct ofp_multipart *mp; - struct ibuf *ibuf; - int rv = -1; - - if ((ibuf = ibuf_static()) == NULL) - return (-1); - - if ((mp = ofp13_multipart_request(con, ibuf, OFP_MP_T_DESC, 0)) == NULL) - goto done; - - oh = &mp->mp_oh; - oh->oh_length = htons(sizeof(*mp)); - if (ofp13_validate(sc, &con->con_local, &con->con_peer, oh, ibuf) != 0) - goto done; - - rv = ofp_output(con, NULL, ibuf); - - done: - ibuf_free(ibuf); - return (rv); -} - -int -ofp13_flow_stats(struct switchd *sc, struct switch_connection *con, - uint32_t out_port, uint32_t out_group, uint8_t table_id) -{ - struct ofp_header *oh; - struct ofp_multipart *mp; - struct ofp_flow_stats_request *fsr; - struct ofp_match *om; - struct ibuf *ibuf; - int padsize, rv = -1; - - if ((ibuf = ibuf_static()) == NULL) - return (-1); - - if ((mp = ofp13_multipart_request(con, ibuf, OFP_MP_T_FLOW, 0)) == NULL) - goto done; - if ((fsr = ibuf_advance(ibuf, sizeof(*fsr))) == NULL) - goto done; - - oh = &mp->mp_oh; - fsr->fsr_table_id = table_id; - fsr->fsr_out_port = htonl(out_port); - fsr->fsr_out_group = htonl(out_group); - - om = &fsr->fsr_match; - om->om_type = htons(OFP_MATCH_OXM); - om->om_length = htons(sizeof(*om)); - padsize = OFP_ALIGN(sizeof(*om)) - sizeof(*om); - if (padsize && ibuf_advance(ibuf, padsize) == NULL) - goto done; - - oh->oh_length = htons(ibuf_length(ibuf)); - if (ofp13_validate(sc, &con->con_local, &con->con_peer, oh, ibuf) != 0) - goto done; - - rv = ofp_output(con, NULL, ibuf); - - done: - ibuf_free(ibuf); - return (rv); -} - -int -ofp13_table_features(struct switchd *sc, struct switch_connection *con, - uint8_t tableid) -{ - struct ofp_header *oh; - struct ofp_multipart *mp; - struct ibuf *ibuf; - int rv = -1; - - if ((ibuf = ibuf_static()) == NULL) - return (-1); - - if ((mp = ofp13_multipart_request(con, ibuf, - OFP_MP_T_TABLE_FEATURES, 0)) == NULL) - goto done; - - oh = &mp->mp_oh; - oh->oh_length = htons(sizeof(*mp)); - if (ofp13_validate(sc, &con->con_local, &con->con_peer, oh, ibuf) != 0) - goto done; - - rv = ofp_output(con, NULL, ibuf); - - done: - ibuf_free(ibuf); - return (rv); -} - -int -ofp13_error(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf, uint16_t type, uint16_t code) -{ - struct ibuf *obuf; - struct ofp_error *err; - struct ofp_header *header; - int dlen, rv = -1; - - if ((obuf = ibuf_static()) == NULL || - (err = ibuf_advance(obuf, sizeof(*err))) == NULL) - goto done; - - header = &err->err_oh; - err->err_type = htons(type); - err->err_code = htons(code); - - /* Copy the first message bytes for the error payload. */ - dlen = ibuf_size(ibuf); - if (dlen > OFP_ERRDATA_MAX) - dlen = OFP_ERRDATA_MAX; - if (ibuf_add(obuf, ibuf_seek(ibuf, 0, dlen), dlen) == -1) - goto done; - - header->oh_version = OFP_V_1_3; - header->oh_type = OFP_T_ERROR; - header->oh_length = htons(ibuf_length(obuf)); - header->oh_xid = oh->oh_xid; - if (ofp13_validate(sc, &con->con_peer, &con->con_local, header, - obuf) == -1) - goto done; - - rv = ofp_output(con, NULL, obuf); - - done: - ibuf_free(obuf); - return (rv); -} - -/* - * The valid commands for groups are: - * OFP_GROUPCMD_{ADD,MODIFY,DELETE} - * - * The valid type for groups are: - * OFP_GROUP_T_{ALL,SELECT,INDIRECT,FAST_FAILOVER} - * - * You have to update the gm->gm_oh.oh_length = htons(ibuf_length(ibuf)); - */ -struct ofp_group_mod * -ofp13_group(struct switch_connection *con, struct ibuf *ibuf, - uint32_t gid, uint16_t cmd, uint8_t type) -{ - struct ofp_group_mod *gm; - struct ofp_header *oh; - - if ((gm = ibuf_advance(ibuf, sizeof(*gm))) == NULL) - return (NULL); - - oh = &gm->gm_oh; - oh->oh_version = OFP_V_1_3; - oh->oh_type = OFP_T_GROUP_MOD; - oh->oh_xid = htonl(con->con_xidnxt++); - gm->gm_command = htons(cmd); - gm->gm_type = type; - gm->gm_group_id = htonl(gid); - return (gm); -} - -/* Remember to update b->b_len. */ -struct ofp_bucket * -ofp13_bucket(struct ibuf *ibuf, uint16_t weight, uint32_t watchport, - uint32_t watchgroup) -{ - struct ofp_bucket *b; - - if ((b = ibuf_advance(ibuf, sizeof(*b))) == NULL) - return (NULL); - - b->b_weight = htons(weight); - b->b_watch_port = htonl(watchport); - b->b_watch_group = htonl(watchgroup); - return (b); -} - -int -ofp13_setconfig_validate(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_switch_config *cfg; - - if ((cfg = ibuf_seek(ibuf, 0, sizeof(*cfg))) == NULL) - return (-1); - - log_debug("\tflags %#04x miss_send_len %s", - ntohs(cfg->cfg_flags), print_map(ntohs(cfg->cfg_miss_send_len), - ofp_controller_maxlen_map)); - return (0); -} - -int -ofp13_setconfig(struct switchd *sc, struct switch_connection *con, - uint16_t flags, uint16_t misslen) -{ - struct ibuf *ibuf; - struct ofp_switch_config *cfg; - struct ofp_header *oh; - int rv = -1; - - if ((ibuf = ibuf_static()) == NULL || - (cfg = ibuf_advance(ibuf, sizeof(*cfg))) == NULL) - goto done; - - cfg->cfg_flags = htons(flags); - cfg->cfg_miss_send_len = htons(misslen); - - oh = &cfg->cfg_oh; - oh->oh_version = OFP_V_1_3; - oh->oh_type = OFP_T_SET_CONFIG; - oh->oh_length = htons(ibuf_length(ibuf)); - oh->oh_xid = htonl(con->con_xidnxt++); - if (ofp13_validate(sc, &con->con_local, &con->con_peer, oh, ibuf) != 0) - goto done; - - rv = ofp_output(con, NULL, ibuf); - - done: - ibuf_free(ibuf); - return (rv); -} - -/* - * Flow modification message. - * - * After the flow-mod header we have N OXM filters to match packets, when - * you finish adding them you must update match header: - * fm_match.om_length = sizeof(fm_match) + OXM length. - * - * Then you must add flow instructions and update the OFP header length: - * fm_oh.oh_length = - * sizeof(*fm) + (fm_match.om_len - sizeof(fm_match)) + instructionslen. - * or - * fm_oh.oh_length = ibuf_length(ibuf). - * - * Note on match payload: - * After adding all matches and before starting to insert instructions you - * must add the mandatory padding to fm_match. You can calculate the padding - * size with this formula: - * padsize = OFP_ALIGN(fm_match.om_length) - fm_match.om_length; - * - * Note on Table-miss: - * To make a table miss you need to set priority 0 and don't add any - * matches, just instructions. - */ -struct ofp_flow_mod * -ofp13_flowmod(struct switch_connection *con, struct ibuf *ibuf, - uint8_t cmd) -{ - struct ofp_flow_mod *fm; - - if ((fm = ibuf_advance(ibuf, sizeof(*fm))) == NULL) - return (NULL); - - fm->fm_oh.oh_version = OFP_V_1_3; - fm->fm_oh.oh_type = OFP_T_FLOW_MOD; - fm->fm_oh.oh_length = htons(sizeof(*fm)); - fm->fm_oh.oh_xid = htonl(con->con_xidnxt++); - - fm->fm_command = cmd; - fm->fm_buffer_id = htonl(OFP_PKTOUT_NO_BUFFER); - fm->fm_flags = htons(OFP_FLOWFLAG_SEND_FLOW_REMOVED); - - fm->fm_match.om_type = htons(OFP_MATCH_OXM); - fm->fm_match.om_length = htons(sizeof(fm->fm_match)); - - return (fm); -} - -int -ofp13_tablemiss_sendctrl(struct switchd *sc, struct switch_connection *con, - uint8_t table) -{ - struct oflowmod_ctx ctx; - struct ibuf *ibuf; - int ret; - - if ((ibuf = oflowmod_open(&ctx, con, NULL, OFP_V_1_3)) == NULL) - goto err; - - if (oflowmod_iopen(&ctx) == -1) - goto err; - - /* Update header */ - ctx.ctx_fm->fm_table_id = table; - - if (oflowmod_instruction(&ctx, - OFP_INSTRUCTION_T_APPLY_ACTIONS) == -1) - goto err; - if (action_output(ibuf, OFP_PORT_CONTROLLER, - OFP_CONTROLLER_MAXLEN_MAX) == -1) - goto err; - - if (oflowmod_iclose(&ctx) == -1) - goto err; - if (oflowmod_close(&ctx) == -1) - goto err; - - if (ofp13_validate(sc, &con->con_local, &con->con_peer, - &ctx.ctx_fm->fm_oh, ibuf) != 0) - goto err; - - ret = ofp_output(con, NULL, ibuf); - ibuf_release(ibuf); - - return (ret); - - err: - (void)oflowmod_err(&ctx, __func__, __LINE__); - return (-1); -} - -int -ofp13_switchconfigure(struct switchd *sc, struct switch_connection *con) -{ - struct switch_table *st; - - /* Look for a table with 'apply' and 'output' support for miss. */ - TAILQ_FOREACH(st, &con->con_stlist, st_entry) { - if ((st->st_instructionsmiss & - (1ULL << OFP_INSTRUCTION_T_APPLY_ACTIONS)) == 0) - continue; - if ((st->st_actionsmiss & (1ULL << OFP_ACTION_OUTPUT)) == 0) - continue; - - break; - } - if (st == NULL) { - log_warn("No apply output for this switch"); - return (-1); - } - - /* Install the flow to receive packets from the switch. */ - return (ofp13_tablemiss_sendctrl(sc, con, st->st_table)); -} - -int -ofp13_getflowtable(struct switch_connection *con) -{ - struct switch_table *st; - - /* Look for a table with 'apply' and 'output' support. */ - TAILQ_FOREACH(st, &con->con_stlist, st_entry) { - if ((st->st_instructions & - (1ULL << OFP_INSTRUCTION_T_APPLY_ACTIONS)) == 0) - continue; - if ((st->st_actions & (1ULL << OFP_ACTION_OUTPUT)) == 0) - continue; - - break; - } - if (st == NULL) - return (-1); - - return (st->st_table); -} diff --git a/usr.sbin/switchd/ofp_common.c b/usr.sbin/switchd/ofp_common.c deleted file mode 100644 index 323ce04a568..00000000000 --- a/usr.sbin/switchd/ofp_common.c +++ /dev/null @@ -1,1488 +0,0 @@ -/* $OpenBSD: ofp_common.c,v 1.11 2019/11/21 06:22:57 akoshibe Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * Copyright (c) 2016 Rafael Zalamena - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" -#include "ofp_map.h" - -int ofp_setversion(struct switch_connection *, int); - -int -ofp_validate_header(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, uint8_t version) -{ - struct constmap *tmap; - - /* For debug, don't verify the header if the version is unset */ - if (version != OFP_V_0 && - (oh->oh_version != version || - oh->oh_type >= OFP_T_TYPE_MAX)) - return (-1); - - switch (version) { - case OFP_V_1_0: - case OFP_V_1_1: - tmap = ofp10_t_map; - break; - case OFP_V_1_3: - default: - tmap = ofp_t_map; - break; - } - - log_debug("%s > %s: version %s type %s length %u xid %u", - print_host(src, NULL, 0), - print_host(dst, NULL, 0), - print_map(oh->oh_version, ofp_v_map), - print_map(oh->oh_type, tmap), - ntohs(oh->oh_length), ntohl(oh->oh_xid)); - - return (0); -} - -int -ofp_validate(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf, uint8_t version) -{ - switch (version) { - case OFP_V_1_0: - return (ofp10_validate(sc, src, dst, oh, ibuf)); - case OFP_V_1_3: - return (ofp13_validate(sc, src, dst, oh, ibuf)); - default: - return (-1); - } - - /* NOTREACHED */ -} - -int -ofp_output(struct switch_connection *con, struct ofp_header *oh, - struct ibuf *obuf) -{ - struct ibuf *buf; - - if ((buf = ibuf_static()) == NULL) - return (-1); - if ((oh != NULL) && - (ibuf_add(buf, oh, sizeof(*oh)) == -1)) { - ibuf_release(buf); - return (-1); - } - if ((obuf != NULL) && - (ibuf_cat(buf, obuf) == -1)) { - ibuf_release(buf); - return (-1); - } - - ofrelay_write(con, buf); - - return (0); -} - -int -ofp_send_hello(struct switchd *sc, struct switch_connection *con, int version) -{ - struct ofp_hello_element_header *he; - struct ofp_header *oh; - struct ibuf *ibuf; - size_t hstart, hend; - uint32_t *bmp; - int rv = -1; - - if ((ibuf = ibuf_static()) == NULL || - (oh = ibuf_advance(ibuf, sizeof(*oh))) == NULL || - (he = ibuf_advance(ibuf, sizeof(*he))) == NULL) - goto done; - - /* Write down all versions we support. */ - hstart = ibuf->wpos; - if ((bmp = ibuf_advance(ibuf, sizeof(*bmp))) == NULL) - goto done; - - *bmp = htonl((1 << OFP_V_1_0) | (1 << OFP_V_1_3)); - hend = ibuf->wpos; - - /* Fill the headers. */ - oh->oh_version = version; - oh->oh_type = OFP_T_HELLO; - oh->oh_length = htons(ibuf_length(ibuf)); - oh->oh_xid = htonl(con->con_xidnxt++); - he->he_type = htons(OFP_HELLO_T_VERSION_BITMAP); - he->he_length = htons(sizeof(*he) + (hend - hstart)); - - if (ofp_validate(sc, &con->con_local, &con->con_peer, oh, ibuf, - version) != 0) - goto done; - - rv = ofp_output(con, NULL, ibuf); - - done: - ibuf_free(ibuf); - return (rv); -} - -int -ofp_validate_hello(struct switchd *sc, - struct sockaddr_storage *src, struct sockaddr_storage *dst, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_hello_element_header *he; - uint32_t *bmp; - off_t poff; - int helen, i, ver; - - /* No extra element headers. */ - if (ntohs(oh->oh_length) == sizeof(*oh)) - return (0); - - /* Test for supported element headers. */ - if ((he = ibuf_seek(ibuf, sizeof(*oh), sizeof(*he))) == NULL) - return (-1); - if (he->he_type != htons(OFP_HELLO_T_VERSION_BITMAP)) - return (-1); - - log_debug("\tversion bitmap:"); - - /* Validate header sizes. */ - helen = ntohs(he->he_length); - if (helen < (int)sizeof(*he)) - return (-1); - else if (helen == sizeof(*he)) - return (0); - - helen -= sizeof(*he); - /* Invalid bitmap size. */ - if ((helen % sizeof(*bmp)) != 0) - return (-1); - - ver = 0; - poff = sizeof(*oh) + sizeof(*he); - while (helen > 0) { - if ((bmp = ibuf_seek(ibuf, poff, sizeof(*bmp))) == NULL) - return (-1); - - for (i = 0; i < 32; i++, ver++) { - if ((ntohl(*bmp) & (1 << i)) == 0) - continue; - - log_debug("\t\tversion %s", - print_map(ver, ofp_v_map)); - } - - helen -= sizeof(*bmp); - poff += sizeof(*bmp); - } - - return (0); -} - -int -ofp_setversion(struct switch_connection *con, int version) -{ - switch (version) { - case OFP_V_1_0: - case OFP_V_1_3: - con->con_version = version; - return (0); - - default: - return (-1); - } -} - -int -ofp_recv_hello(struct switchd *sc, struct switch_connection *con, - struct ofp_header *oh, struct ibuf *ibuf) -{ - struct ofp_hello_element_header *he; - uint32_t *bmp; - off_t poff; - int helen, i, ver; - - /* No extra element headers, just use the header version. */ - if (ntohs(oh->oh_length) == sizeof(*oh)) - return (ofp_setversion(con, oh->oh_version)); - - /* Read the element header. */ - if ((he = ibuf_seek(ibuf, sizeof(*oh), sizeof(*he))) == NULL) - return (-1); - - /* We don't support anything else than the version bitmap. */ - if (he->he_type != htons(OFP_HELLO_T_VERSION_BITMAP)) - return (-1); - - /* Validate header sizes. */ - helen = ntohs(he->he_length); - if (helen < (int)sizeof(*he)) - return (-1); - else if (helen == sizeof(*he)) - return (ofp_setversion(con, oh->oh_version)); - - helen -= sizeof(*he); - /* Invalid bitmap size. */ - if ((helen % sizeof(*bmp)) != 0) - return (-1); - - ver = 0; - poff = sizeof(*oh) + sizeof(*he); - - /* Loop through the bitmaps and choose the higher version. */ - while (helen > 0) { - if ((bmp = ibuf_seek(ibuf, poff, sizeof(*bmp))) == NULL) - return (-1); - - for (i = 0; i < 32; i++, ver++) { - if ((ntohl(*bmp) & (1 << i)) == 0) - continue; - - ofp_setversion(con, ver); - } - - helen -= sizeof(*bmp); - poff += sizeof(*bmp); - } - - /* Check if we have set any version, otherwise fallback. */ - if (con->con_version == OFP_V_0) - return (ofp_setversion(con, oh->oh_version)); - - return (0); -} - -int -ofp_send_featuresrequest(struct switchd *sc, struct switch_connection *con) -{ - struct ofp_header *oh; - struct ibuf *ibuf; - int rv = -1; - - if ((ibuf = ibuf_static()) == NULL || - (oh = ibuf_advance(ibuf, sizeof(*oh))) == NULL) - return (-1); - - oh->oh_version = con->con_version; - oh->oh_type = OFP_T_FEATURES_REQUEST; - oh->oh_length = htons(ibuf_length(ibuf)); - oh->oh_xid = htonl(con->con_xidnxt++); - if (ofp_validate(sc, &con->con_local, &con->con_peer, oh, ibuf, - con->con_version) != 0) - goto done; - - rv = ofp_output(con, NULL, ibuf); - - done: - ibuf_free(ibuf); - return (rv); -} - -/* Appends an action with just the generic header. */ -int -action_new(struct ibuf *ibuf, uint16_t type) -{ - struct ofp_action_header *ah; - - if ((ah = ibuf_advance(ibuf, sizeof(*ah))) == NULL) - return (-1); - - ah->ah_type = htons(type); - ah->ah_len = htons(sizeof(*ah)); - return (0); -} - -int -action_group(struct ibuf *ibuf, uint32_t group) -{ - struct ofp_action_group *ag; - - if ((ag = ibuf_advance(ibuf, sizeof(*ag))) == NULL) - return (-1); - - ag->ag_type = htons(OFP_ACTION_GROUP); - ag->ag_len = sizeof(*ag); - ag->ag_group_id = htonl(group); - return (0); -} - -int -action_output(struct ibuf *ibuf, uint32_t port, uint16_t maxlen) -{ - struct ofp_action_output *ao; - - if ((ao = ibuf_advance(ibuf, sizeof(*ao))) == NULL) - return (-1); - - ao->ao_type = htons(OFP_ACTION_OUTPUT); - ao->ao_len = htons(sizeof(*ao)); - ao->ao_port = htonl(port); - ao->ao_max_len = htons(maxlen); - return (0); -} - -/* - * This action pushes VLAN/MPLS/PBB tags into the outermost part of the - * packet. When the type is X ethertype must be Y: - * - OFP_ACTION_PUSH_VLAN: ETHERTYPE_VLAN or ETHERTYPE_QINQ. - * - OFP_ACTION_PUSH_MPLS: ETHERTYPE_MPLS or ETHERTYPE_MPLSCAST. - * - OFP_ACTION_PUSH_PBB: ETHERTYPE_??? (0x88E7). - */ -int -action_push(struct ibuf *ibuf, uint16_t type, uint16_t ethertype) -{ - struct ofp_action_push *ap; - - if ((ap = ibuf_advance(ibuf, sizeof(*ap))) == NULL) - return (-1); - - ap->ap_type = htons(type); - ap->ap_len = htons(sizeof(*ap)); - ap->ap_ethertype = htons(ethertype); - return (0); -} - -/* - * This action only pops the outermost VLAN tag and only one at a time, - * you can only pop multiple VLANs with an action list that is only - * availiable for OFP_INSTRUCTION_T_APPLY_ACTIONS. - */ -int -action_pop_vlan(struct ibuf *ibuf) -{ - return (action_new(ibuf, OFP_ACTION_POP_VLAN)); -} - -/* - * Use this with caution since this will pop MPLS shim regardless of the - * BoS bit state. - */ -int -action_pop_mpls(struct ibuf *ibuf, uint16_t ethertype) -{ - struct ofp_action_pop_mpls *apm; - - if ((apm = ibuf_advance(ibuf, sizeof(*apm))) == NULL) - return (-1); - - apm->apm_type = htons(OFP_ACTION_POP_MPLS); - apm->apm_len = htons(sizeof(*apm)); - apm->apm_ethertype = htons(ethertype); - return (0); -} - -int -action_copyttlout(struct ibuf *ibuf) -{ - return (action_new(ibuf, OFP_ACTION_COPY_TTL_OUT)); -} - -int -action_copyttlin(struct ibuf *ibuf) -{ - return (action_new(ibuf, OFP_ACTION_COPY_TTL_IN)); -} - -int -action_decnwttl(struct ibuf *ibuf) -{ - return (action_new(ibuf, OFP_ACTION_DEC_NW_TTL)); -} - -/* - * This function should be used with the oxm_*() family. - * - * After filling the action_setfield() with oxms you have to set the - * asf_len with htons(size_of_oxms). - */ -struct ofp_action_set_field * -action_setfield(struct ibuf *ibuf) -{ - struct ofp_action_set_field *asf; - - if ((asf = ibuf_advance(ibuf, sizeof(*asf))) == NULL) - return (NULL); - - asf->asf_type = htons(OFP_ACTION_SET_FIELD); - return (asf); -} - -struct ofp_ox_match * -oxm_get(struct ibuf *ibuf, uint16_t field, int hasmask, uint8_t len) -{ - struct ofp_ox_match *oxm; - size_t oxmlen; - - /* - * When the mask is used we must always reserve double the space, - * because the mask field is the same size of the value. - */ - if (hasmask) - len = len * 2; - - oxmlen = sizeof(*oxm) + len; - if ((oxm = ibuf_advance(ibuf, oxmlen)) == NULL) - return (NULL); - - oxm->oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC); - oxm->oxm_length = len; - OFP_OXM_SET_FIELD(oxm, field); - if (hasmask) - OFP_OXM_SET_HASMASK(oxm); - - return (oxm); -} - -/* - * OpenFlow port where the packet where received. - * May be a physical port, a logical port or the reserved port OFPP_LOCAL. - */ -int -oxm_inport(struct ibuf *ibuf, uint32_t in_port) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_IN_PORT, 0, - sizeof(in_port))) == NULL) - return (-1); - - in_port = htonl(in_port); - memcpy(oxm->oxm_value, &in_port, sizeof(in_port)); - return (0); -} - -/* - * Physical port on which the packet was received. - * Requires: oxm_inport. - */ -int -oxm_inphyport(struct ibuf *ibuf, uint32_t in_phy_port) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_IN_PHY_PORT, 0, - sizeof(in_phy_port))) == NULL) - return (-1); - - in_phy_port = htonl(in_phy_port); - memcpy(oxm->oxm_value, &in_phy_port, sizeof(in_phy_port)); - return (0); -} - -/* Table metadata. */ -int -oxm_metadata(struct ibuf *ibuf, int hasmask, uint64_t metadata, uint64_t mask) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_META, hasmask, - sizeof(metadata))) == NULL) - return (-1); - - metadata = htobe64(metadata); - memcpy(oxm->oxm_value, &metadata, sizeof(metadata)); - if (hasmask) { - mask = htobe64(mask); - memcpy(oxm->oxm_value + sizeof(metadata), &mask, sizeof(mask)); - } - - return (0); -} - -int -oxm_etheraddr(struct ibuf *ibuf, int issrc, uint8_t *addr, uint8_t *mask) -{ - struct ofp_ox_match *oxm; - int type; - int hasmask = (mask != NULL); - - type = issrc ? OFP_XM_T_ETH_SRC : OFP_XM_T_ETH_DST; - if ((oxm = oxm_get(ibuf, type, hasmask, ETHER_ADDR_LEN)) == NULL) - return (-1); - - memcpy(oxm->oxm_value, addr, ETHER_ADDR_LEN); - if (hasmask) - memcpy(oxm->oxm_value + ETHER_ADDR_LEN, mask, ETHER_ADDR_LEN); - - return (0); -} - -int -oxm_ethertype(struct ibuf *ibuf, uint16_t type) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_ETH_TYPE, 0, sizeof(type))) == NULL) - return (-1); - - type = htons(type); - memcpy(oxm->oxm_value, &type, sizeof(type)); - return (0); -} - -int -oxm_vlanvid(struct ibuf *ibuf, int hasmask, uint16_t vid, uint16_t mask) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_VLAN_VID, hasmask, - sizeof(vid))) == NULL) - return (-1); - - /* VID uses only the 13 least significant bits. */ - vid &= 0x1fff; - vid = htons(vid); - memcpy(oxm->oxm_value, &vid, sizeof(vid)); - if (hasmask) { - mask &= 0x1fff; - mask = htons(mask); - memcpy(oxm->oxm_value + sizeof(vid), &mask, sizeof(mask)); - } - - return (0); -} - -/* - * 802.1Q Prio from the outermost tag. - * - * Requires: oxm_vlanvid. - */ -int -oxm_vlanpcp(struct ibuf *ibuf, uint8_t pcp) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_VLAN_PCP, 0, sizeof(pcp))) == NULL) - return (-1); - - /* PCP only uses the lower 3 bits. */ - pcp &= 0x07; - memcpy(oxm->oxm_value, &pcp, sizeof(pcp)); - return (0); -} - -/* - * The Diff Serv Code Point (DSCP) bits avaliable in IPv4 ToS field or - * IPv6 Traffic Class field. - * - * Requires: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6). - */ -int -oxm_ipdscp(struct ibuf *ibuf, uint8_t dscp) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_IP_DSCP, 0, sizeof(dscp))) == NULL) - return (-1); - - /* Only the 6 lower bits have meaning. */ - dscp &= 0x3F; - memcpy(oxm->oxm_value, &dscp, sizeof(dscp)); - return (0); -} - -/* - * The ECN (Explicit Congestion Notification) bits of IP headers. - * - * Requires: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6). - */ -int -oxm_ipecn(struct ibuf *ibuf, uint8_t ecn) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_IP_ECN, 0, sizeof(ecn))) == NULL) - return (-1); - - /* Only the 2 most significant bits have meaning. */ - ecn &= 0x03; - memcpy(oxm->oxm_value, &ecn, sizeof(ecn)); - return (0); -} - -/* - * The IP protocol byte. - * - * Requires: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6). - */ -int -oxm_ipproto(struct ibuf *ibuf, uint8_t proto) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_IP_PROTO, 0, sizeof(proto))) == NULL) - return (-1); - - memcpy(oxm->oxm_value, &proto, sizeof(proto)); - return (0); -} - -/* - * The IPv4 address source/destination. - * - * Requires: oxm_ethertype(ETHERTYPE_IP). - */ -int -oxm_ipaddr(struct ibuf *ibuf, int issrc, int hasmask, uint32_t addr, - uint32_t mask) -{ - struct ofp_ox_match *oxm; - int type; - - type = issrc ? OFP_XM_T_IPV4_SRC : OFP_XM_T_IPV4_DST; - if ((oxm = oxm_get(ibuf, type, hasmask, sizeof(addr))) == NULL) - return (-1); - - addr = htonl(addr); - memcpy(oxm->oxm_value, &addr, sizeof(addr)); - if (hasmask) { - mask = htonl(mask); - memcpy(oxm->oxm_value + sizeof(addr), &mask, sizeof(mask)); - } - - return (0); -} - -/* - * The TCP source/destination port. - * - * Requirements: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6) - * and oxm_ipproto(IPPROTO_TCP). - */ -int -oxm_tcpport(struct ibuf *ibuf, int issrc, uint16_t port) -{ - struct ofp_ox_match *oxm; - int type; - - type = issrc ? OFP_XM_T_TCP_SRC : OFP_XM_T_TCP_DST; - if ((oxm = oxm_get(ibuf, type, 0, sizeof(port))) == NULL) - return (-1); - - port = htons(port); - memcpy(oxm->oxm_value, &port, sizeof(port)); - return (0); -} - -/* - * The UDP source/destination port. - * - * Requirements: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6) - * and oxm_ipproto(IPPROTO_UDP). - */ -int -oxm_udpport(struct ibuf *ibuf, int issrc, uint16_t port) -{ - struct ofp_ox_match *oxm; - int type; - - type = issrc ? OFP_XM_T_UDP_SRC : OFP_XM_T_UDP_DST; - if ((oxm = oxm_get(ibuf, type, 0, sizeof(port))) == NULL) - return (-1); - - port = htons(port); - memcpy(oxm->oxm_value, &port, sizeof(port)); - return (0); -} - -/* - * The SCTP source/destination port. - * - * Requirements: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6) - * and oxm_ipproto(IPPROTO_??? -- 132). - */ -int -oxm_sctpport(struct ibuf *ibuf, int issrc, uint16_t port) -{ - struct ofp_ox_match *oxm; - int type; - - type = issrc ? OFP_XM_T_SCTP_SRC : OFP_XM_T_SCTP_DST; - if ((oxm = oxm_get(ibuf, type, 0, sizeof(port))) == NULL) - return (-1); - - port = htons(port); - memcpy(oxm->oxm_value, &port, sizeof(port)); - return (0); -} - -/* - * The ICMPv4 type in the ICMP header. - * - * Requires: oxm_ethertype(ETHERTYPE_IP) and oxm_ipproto(IPPROTO_ICMP). - */ -int -oxm_icmpv4type(struct ibuf *ibuf, uint8_t type) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_ICMPV4_TYPE, 0, - sizeof(type))) == NULL) - return (-1); - - memcpy(oxm->oxm_value, &type, sizeof(type)); - return (0); -} - -/* - * The ICMPv4 code in the ICMP header. - * - * Requires: oxm_ethertype(ETHERTYPE_IP) and oxm_ipproto(IPPROTO_ICMP). - */ -int -oxm_icmpv4code(struct ibuf *ibuf, uint8_t code) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_ICMPV4_CODE, 0, - sizeof(code))) == NULL) - return (-1); - - memcpy(oxm->oxm_value, &code, sizeof(code)); - return (0); -} - -/* - * ARP opcode. - * - * Requires: oxm_ethertype(ETHERTYPE_ARP). - */ -int -oxm_arpop(struct ibuf *ibuf, uint16_t op) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_ARP_OP, 0, sizeof(op))) == NULL) - return (-1); - - op = htons(op); - memcpy(oxm->oxm_value, &op, sizeof(op)); - return (0); -} - -/* - * ARP source/target protocol address. - * - * Requires: oxm_ethertype(ETHERTYPE_ARP). - */ -int -oxm_arpaddr(struct ibuf *ibuf, int issrc, int hasmask, uint32_t addr, - uint32_t mask) -{ - struct ofp_ox_match *oxm; - int type; - - type = issrc ? OFP_XM_T_ARP_SPA : OFP_XM_T_ARP_TPA; - if ((oxm = oxm_get(ibuf, type, hasmask, sizeof(addr))) == NULL) - return (-1); - - addr = htonl(addr); - memcpy(oxm->oxm_value, &addr, sizeof(addr)); - if (hasmask) { - mask = htonl(mask); - memcpy(oxm->oxm_value + sizeof(addr), &mask, sizeof(mask)); - } - - return (0); -} - -/* - * ARP source/target hardware address. - * - * Requires: oxm_ethertype(ETHERTYPE_ARP). - */ -int -oxm_arphaddr(struct ibuf *ibuf, int issrc, uint8_t *addr, uint8_t *mask) -{ - struct ofp_ox_match *oxm; - int type; - int hasmask = (mask != NULL); - - type = issrc ? OFP_XM_T_ARP_SHA : OFP_XM_T_ARP_THA; - if ((oxm = oxm_get(ibuf, type, hasmask, ETHER_ADDR_LEN)) == NULL) - return (-1); - - memcpy(oxm->oxm_value, addr, ETHER_ADDR_LEN); - if (hasmask) - memcpy(oxm->oxm_value + ETHER_ADDR_LEN, mask, ETHER_ADDR_LEN); - - return (0); -} - -/* - * The source or destination of the IPv6 address. - * - * Requirements: oxm_ethertype(ETHERTYPE_IPV6). - */ -int -oxm_ipv6addr(struct ibuf *ibuf, int issrc, struct in6_addr *addr, - struct in6_addr *mask) -{ - struct ofp_ox_match *oxm; - int type; - int hasmask = (mask != NULL); - - type = issrc ? OFP_XM_T_IPV6_SRC : OFP_XM_T_IPV6_DST; - if ((oxm = oxm_get(ibuf, type, hasmask, sizeof(*addr))) == NULL) - return (-1); - - memcpy(oxm->oxm_value, addr, sizeof(*addr)); - if (hasmask) - memcpy(oxm->oxm_value + sizeof(*addr), mask, sizeof(*mask)); - - return (0); -} - -/* - * The IPv6 flow label field. - * - * Requirements: oxm_ethertype(ETHERTYPE_IPV6). - */ -int -oxm_ipv6flowlabel(struct ibuf *ibuf, int hasmask, uint32_t flowlabel, - uint32_t mask) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_IPV6_FLABEL, hasmask, - sizeof(flowlabel))) == NULL) - return (-1); - - /* - * 12 most significants bits forced to 0 and only the 20 lowers - * bits have meaning. - */ - flowlabel &= 0x000FFFFFU; - flowlabel = htonl(flowlabel); - memcpy(oxm->oxm_value, &flowlabel, sizeof(flowlabel)); - if (hasmask) { - mask &= 0x000FFFFFU; - mask = htonl(mask); - memcpy(oxm->oxm_value + sizeof(flowlabel), &mask, sizeof(mask)); - } - - return (0); -} - -/* - * The ICMPv6 type in ICMP header. - * - * Requirements: oxm_ethertype(ETHERTYPE_IPV6) and oxm_ipproto(IPPROTO_ICMPV6). - */ -int -oxm_icmpv6type(struct ibuf *ibuf, uint8_t type) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_ICMPV6_TYPE, 0, - sizeof(type))) == NULL) - return (-1); - - memcpy(oxm->oxm_value, &type, sizeof(type)); - return (0); -} - -/* - * The ICMPv6 code in ICMP header. - * - * Requirements: oxm_ethertype(ETHERTYPE_IPV6) and oxm_ipproto(IPPROTO_ICMPV6). - */ -int -oxm_icmpv6code(struct ibuf *ibuf, uint8_t code) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_ICMPV6_CODE, 0, - sizeof(code))) == NULL) - return (-1); - - memcpy(oxm->oxm_value, &code, sizeof(code)); - return (0); -} - -/* - * The target address in neighbour discovery message. - * - * Requirements: oxm_ethertype(ETHERTYPE_IPV6), oxm_ipproto(IPPROTO_ICMPV6) - * and oxm_icmpv6type(ND_NEIGHBOR_SOLICIT) or - * oxm_icmpv6type(ND_NEIGHBOR_ADVERT). - */ -int -oxm_ipv6ndtarget(struct ibuf *ibuf, struct in6_addr *addr) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_IPV6_ND_TARGET, 0, - sizeof(*addr))) == NULL) - return (-1); - - memcpy(oxm->oxm_value, addr, sizeof(*addr)); - return (0); -} - -/* - * The source link-layer address in an IPv6 Neighbour discovery. - * - * Requirements: oxm_ethertype(ETHERTYPE_IPV6), oxm_ipproto(IPPROTO_ICMPV6) - * and oxm_icmpv6type(ND_NEIGHBOR_SOLICIT). - */ -int -oxm_ipv6ndlinkaddr(struct ibuf *ibuf, int issrc, uint8_t *addr) -{ - struct ofp_ox_match *oxm; - int type; - - type = issrc ? OFP_XM_T_IPV6_ND_SLL : OFP_XM_T_IPV6_ND_TLL; - if ((oxm = oxm_get(ibuf, type, 0, ETHER_ADDR_LEN)) == NULL) - return (-1); - - memcpy(oxm->oxm_value, addr, ETHER_ADDR_LEN); - return (0); -} - -/* - * The label in the MPLS shim. - * - * Requirements: oxm_ethertype(ETHERTYPE_MPLS) or - * oxm_ethertype(ETHERTYPE_MPLS_MCAST). - */ -int -oxm_mplslabel(struct ibuf *ibuf, uint32_t label) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_MPLS_LABEL, 0, - sizeof(label))) == NULL) - return (-1); - - label &= MPLS_LABEL_MASK; - label = htonl(label); - memcpy(oxm->oxm_value, &label, sizeof(label)); - return (0); -} - -/* - * The TC in the first MPLS shim. - * - * Requirements: oxm_ethertype(ETHERTYPE_MPLS) or - * oxm_ethertype(ETHERTYPE_MPLS_MCAST). - */ -int -oxm_mplstc(struct ibuf *ibuf, uint8_t tc) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_MPLS_TC, 0, sizeof(tc))) == NULL) - return (-1); - - tc &= 0x07; - memcpy(oxm->oxm_value, &tc, sizeof(tc)); - return (0); -} - -/* - * The BoS bit in the first MPLS shim. - * - * Requirements: oxm_ethertype(ETHERTYPE_MPLS) or - * oxm_ethertype(ETHERTYPE_MPLS_MCAST). - */ -int -oxm_mplsbos(struct ibuf *ibuf, uint8_t bos) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_MPLS_BOS, 0, sizeof(bos))) == NULL) - return (-1); - - bos &= 0x01; - memcpy(oxm->oxm_value, &bos, sizeof(bos)); - return (0); -} - -/* - * Comment shamelessly taken from OpenFlow 1.3.5 specification. - * - * Metadata associated with a logical port. - * - * If the logical port performs encapsulation and decapsulation, this - * is the demultiplexing field from the encapsulation header. - * For example, for a packet received via GRE tunnel including a (32-bit) key, - * the key is stored in the low 32-bits and the high bits are zeroed. - * For a MPLS logical port, the low 20 bits represent the MPLS Label. - * For a VxLAN logical port, the low 24 bits represent the VNI. - * If the packet is not received through a logical port, the value is 0. - */ -int -oxm_tunnelid(struct ibuf *ibuf, int hasmask, uint64_t id, uint64_t mask) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_TUNNEL_ID, hasmask, - sizeof(id))) == NULL) - return (-1); - - id = htobe64(id); - memcpy(oxm->oxm_value, &id, sizeof(id)); - if (hasmask) { - mask = htobe64(mask); - memcpy(oxm->oxm_value + sizeof(id), &mask, sizeof(mask)); - } - return (0); -} - -/* - * The IPv6 extension header. - * - * Tip: use the OFP_XM_IPV6_EXTHDR_* macros. - * - * Requirements: oxm_ethertype(ETHERTYPE_IPV6). - */ -int -oxm_ipv6exthdr(struct ibuf *ibuf, int hasmask, uint16_t exthdr, uint16_t mask) -{ - struct ofp_ox_match *oxm; - - if ((oxm = oxm_get(ibuf, OFP_XM_T_IPV6_EXTHDR, hasmask, - sizeof(exthdr))) == NULL) - return (-1); - - /* Only the lower 9 bits have meaning. */ - exthdr &= 0x01FF; - exthdr = htons(exthdr); - memcpy(oxm->oxm_value, &exthdr, sizeof(exthdr)); - if (hasmask) { - mask &= 0x01FF; - mask = htons(mask); - memcpy(oxm->oxm_value + sizeof(exthdr), &mask, sizeof(mask)); - } - return (0); -} - -/* - * Appends a new instruction with hlen size. - * - * Remember to set the instruction length (i->i_len) if it has more data, - * like ofp_instruction_actions, ofp_instruction_goto_table etc... - */ -struct ofp_instruction * -ofp_instruction(struct ibuf *ibuf, uint16_t type, uint16_t hlen) -{ - struct ofp_instruction *oi; - - if ((oi = ibuf_advance(ibuf, hlen)) == NULL) - return (NULL); - - oi->i_type = htons(type); - oi->i_len = htons(hlen); - return (oi); -} - -struct multipart_message * -ofp_multipart_lookup(struct switch_connection *con, uint32_t xid) -{ - struct multipart_message *mm; - - SLIST_FOREACH(mm, &con->con_mmlist, mm_entry) { - if (mm->mm_xid != xid) - continue; - - return (mm); - } - - return (NULL); -} - -int -ofp_multipart_add(struct switch_connection *con, uint32_t xid, uint8_t type) -{ - struct multipart_message *mm; - - if ((mm = ofp_multipart_lookup(con, xid)) != NULL) { - /* - * A multipart reply has the same xid and type, otherwise - * something went wrong. - */ - if (mm->mm_type != type) - return (-1); - - return (0); - } - - if ((mm = calloc(1, sizeof(*mm))) == NULL) - return (-1); - - mm->mm_xid = xid; - mm->mm_type = type; - SLIST_INSERT_HEAD(&con->con_mmlist, mm, mm_entry); - return (0); -} - -void -ofp_multipart_del(struct switch_connection *con, uint32_t xid) -{ - struct multipart_message *mm; - - SLIST_FOREACH(mm, &con->con_mmlist, mm_entry) - if (mm->mm_xid == xid) - break; - - if (mm == NULL) - return; - - ofp_multipart_free(con, mm); -} - -void -ofp_multipart_free(struct switch_connection *con, - struct multipart_message *mm) -{ - SLIST_REMOVE(&con->con_mmlist, mm, multipart_message, mm_entry); - free(mm); -} - -void -ofp_multipart_clear(struct switch_connection *con) -{ - struct multipart_message *mm; - - while (!SLIST_EMPTY(&con->con_mmlist)) { - mm = SLIST_FIRST(&con->con_mmlist); - ofp_multipart_free(con, mm); - } -} - -struct switch_table * -switch_tablelookup(struct switch_connection *con, int table) -{ - struct switch_table *st; - - TAILQ_FOREACH(st, &con->con_stlist, st_entry) { - if (st->st_table == table) - return (st); - } - - return (NULL); -} - -struct switch_table * -switch_newtable(struct switch_connection *con, int table) -{ - struct switch_table *st; - - if ((st = calloc(1, sizeof(*st))) == NULL) - return (NULL); - - st->st_table = table; - TAILQ_INSERT_TAIL(&con->con_stlist, st, st_entry); - - return (st); -} - -void -switch_deltable(struct switch_connection *con, struct switch_table *st) -{ - TAILQ_REMOVE(&con->con_stlist, st, st_entry); - free(st); -} - -void -switch_freetables(struct switch_connection *con) -{ - struct switch_table *st; - - while (!TAILQ_EMPTY(&con->con_stlist)) { - st = TAILQ_FIRST(&con->con_stlist); - switch_deltable(con, st); - } -} - -int -oflowmod_state(struct oflowmod_ctx *ctx, unsigned int old, unsigned int new) -{ - if (ctx->ctx_state != old) - return (-1); - ctx->ctx_state = new; - return (0); -} - -int -oflowmod_err(struct oflowmod_ctx *ctx, const char *func, int line) -{ - log_debug("%s: function %s line %d state %d", - __func__, func, line, ctx->ctx_state); - - if (ctx->ctx_state >= OFMCTX_ERR) - return (-1); - if (ctx->ctx_flags & OFMCTX_IBUF) - ibuf_release(ctx->ctx_ibuf); - ctx->ctx_state = OFMCTX_ERR; - return (-1); -} - -struct ibuf * -oflowmod_open(struct oflowmod_ctx *ctx, struct switch_connection *con, - struct ibuf *ibuf, uint8_t version) -{ - struct ofp_flow_mod *fm; - struct switch_connection conb; - - switch (version) { - case OFP_V_0: - case OFP_V_1_3: - version = OFP_V_1_3; - break; - default: - log_warnx("%s: unsupported version 0x%02x", __func__, version); - return (NULL); - } - - memset(ctx, 0, sizeof(*ctx)); - - if (oflowmod_state(ctx, OFMCTX_INIT, OFMCTX_OPEN) == -1) - goto err; - - if (ibuf == NULL) { - ctx->ctx_flags |= OFMCTX_IBUF; - if ((ibuf = ibuf_static()) == NULL) - goto err; - } - - ctx->ctx_ibuf = ibuf; - ctx->ctx_start = ibuf->wpos; - - /* - * The connection is not strictly required and might not be - * available in other places; just default to an xid 0. - */ - if (con == NULL) { - con = &conb; - memset(con, 0, sizeof(*con)); - } - - /* uses defaults, can be changed by accessing fm later */ - if ((fm = ofp13_flowmod(con, ibuf, OFP_FLOWCMD_ADD)) == NULL) - goto err; - - ctx->ctx_fm = fm; - - return (ctx->ctx_ibuf); - - err: - (void)oflowmod_err(ctx, __func__, __LINE__); - return (NULL); -} - -int -oflowmod_mopen(struct oflowmod_ctx *ctx) -{ - if (oflowmod_state(ctx, OFMCTX_OPEN, OFMCTX_MOPEN) == -1) - return (oflowmod_err(ctx, __func__, __LINE__)); - - ctx->ctx_ostart = ctx->ctx_start + - offsetof(struct ofp_flow_mod, fm_match); - - return (0); -} - -int -oflowmod_mclose(struct oflowmod_ctx *ctx) -{ - struct ibuf *ibuf = ctx->ctx_ibuf; - struct ofp_flow_mod *fm = ctx->ctx_fm; - size_t omlen, padding; - - if (oflowmod_state(ctx, OFMCTX_MOPEN, OFMCTX_MCLOSE) == -1) - return (oflowmod_err(ctx, __func__, __LINE__)); - - ctx->ctx_oend = ibuf->wpos; - omlen = ctx->ctx_oend - ctx->ctx_ostart; - - /* Update match length */ - fm->fm_match.om_length = htons(omlen); - - padding = OFP_ALIGN(omlen) - omlen; - if (padding) { - ctx->ctx_oend += padding; - if (ibuf_advance(ibuf, padding) == NULL) - return (oflowmod_err(ctx, __func__, __LINE__)); - } - - return (0); -} - -int -oflowmod_iopen(struct oflowmod_ctx *ctx) -{ - struct ibuf *ibuf = ctx->ctx_ibuf; - - if (ctx->ctx_state < OFMCTX_MOPEN && - (oflowmod_mopen(ctx) == -1)) - return (oflowmod_err(ctx, __func__, __LINE__)); - if (ctx->ctx_state < OFMCTX_MCLOSE && - (oflowmod_mclose(ctx) == -1)) - return (oflowmod_err(ctx, __func__, __LINE__)); - - if (oflowmod_state(ctx, OFMCTX_MCLOSE, OFMCTX_IOPEN) == -1) - return (oflowmod_err(ctx, __func__, __LINE__)); - - ctx->ctx_istart = ibuf->wpos; - - return (0); -} - -int -oflowmod_instruction(struct oflowmod_ctx *ctx, unsigned int type) -{ - struct ibuf *ibuf = ctx->ctx_ibuf; - struct ofp_instruction *oi; - size_t len; - - if (ctx->ctx_state < OFMCTX_IOPEN && - (oflowmod_iopen(ctx) == -1)) - return (oflowmod_err(ctx, __func__, __LINE__)); - - if (oflowmod_state(ctx, OFMCTX_IOPEN, OFMCTX_IOPEN) == -1) - return (oflowmod_err(ctx, __func__, __LINE__)); - - if (ctx->ctx_oi != NULL && oflowmod_instructionclose(ctx) == -1) - return (oflowmod_err(ctx, __func__, __LINE__)); - - ctx->ctx_oioff = ibuf->wpos; - - switch (type) { - case OFP_INSTRUCTION_T_GOTO_TABLE: - len = sizeof(struct ofp_instruction_goto_table); - break; - case OFP_INSTRUCTION_T_WRITE_META: - len = sizeof(struct ofp_instruction_write_metadata); - break; - case OFP_INSTRUCTION_T_WRITE_ACTIONS: - case OFP_INSTRUCTION_T_APPLY_ACTIONS: - case OFP_INSTRUCTION_T_CLEAR_ACTIONS: - len = sizeof(struct ofp_instruction_actions); - break; - case OFP_INSTRUCTION_T_METER: - len = sizeof(struct ofp_instruction_meter); - break; - case OFP_INSTRUCTION_T_EXPERIMENTER: - len = sizeof(struct ofp_instruction_experimenter); - break; - default: - return (oflowmod_err(ctx, __func__, __LINE__)); - } - - if ((oi = ofp_instruction(ibuf, type, len)) == NULL) - return (oflowmod_err(ctx, __func__, __LINE__)); - - ctx->ctx_oi = oi; - - return (0); -} - -int -oflowmod_instructionclose(struct oflowmod_ctx *ctx) -{ - struct ibuf *ibuf = ctx->ctx_ibuf; - struct ofp_instruction *oi = ctx->ctx_oi; - size_t oilen; - - if (ctx->ctx_state < OFMCTX_IOPEN || oi == NULL) - return (oflowmod_err(ctx, __func__, __LINE__)); - - oilen = ibuf->wpos - ctx->ctx_oioff; - - if (oilen > UINT16_MAX) - return (oflowmod_err(ctx, __func__, __LINE__)); - - oi->i_len = htons(oilen); - ctx->ctx_oi = NULL; - - return (0); -} - -int -oflowmod_iclose(struct oflowmod_ctx *ctx) -{ - struct ibuf *ibuf = ctx->ctx_ibuf; - - if (oflowmod_state(ctx, OFMCTX_IOPEN, OFMCTX_ICLOSE) == -1) - return (oflowmod_err(ctx, __func__, __LINE__)); - - if (ctx->ctx_oi != NULL && oflowmod_instructionclose(ctx) == -1) - return (-1); - - ctx->ctx_iend = ibuf->wpos; - - return (0); -} - -int -oflowmod_close(struct oflowmod_ctx *ctx) -{ - struct ofp_flow_mod *fm = ctx->ctx_fm; - struct ibuf *ibuf = ctx->ctx_ibuf; - size_t len; - - /* No matches, calculate default */ - if (ctx->ctx_state < OFMCTX_MOPEN && - (oflowmod_mopen(ctx) == -1 || - oflowmod_mclose(ctx) == -1)) - goto err; - - /* No instructions, calculate default */ - if (ctx->ctx_state < OFMCTX_IOPEN && - (oflowmod_iopen(ctx) == -1 || - oflowmod_iclose(ctx) == -1)) - goto err; - - if (oflowmod_state(ctx, OFMCTX_ICLOSE, OFMCTX_CLOSE) == -1) - goto err; - - /* Update length */ - len = ibuf->wpos - ctx->ctx_start; - fm->fm_oh.oh_length = htons(len); - - return (0); - - err: - return (oflowmod_err(ctx, __func__, __LINE__)); - -} diff --git a/usr.sbin/switchd/ofp_map.h b/usr.sbin/switchd/ofp_map.h deleted file mode 100644 index 3519ed175c2..00000000000 --- a/usr.sbin/switchd/ofp_map.h +++ /dev/null @@ -1,74 +0,0 @@ -/* $OpenBSD: ofp_map.h,v 1.9 2016/11/18 16:56:09 reyk Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef OFP_MAP_H -#define OFP_MAP_H - -struct constmap { - unsigned int cm_type; - const char *cm_name; - const char *cm_descr; -}; - -/* - * Each map is generated from lists of #define's in ofp.h, using the format: - * #define OFP_{MAPNAME}_FLAG {value} / * COMMENT * / - * - * Please make sure that the flags in ofp.h match this style (incl. comment) - */ - -/* OpenFlow 1.0 maps */ -extern struct constmap ofp10_t_map[]; -extern struct constmap ofp10_port_map[]; -extern struct constmap ofp10_action_map[]; -extern struct constmap ofp10_wildcard_map[]; -extern struct constmap ofp10_errtype_map[]; -extern struct constmap ofp10_errflowmod_map[]; - -/* OpenFlow 1.3+ maps */ -extern struct constmap ofp_v_map[]; -extern struct constmap ofp_t_map[]; -extern struct constmap ofp_pktin_map[]; -extern struct constmap ofp_port_map[]; -extern struct constmap ofp_pktout_map[]; -extern struct constmap ofp_oxm_c_map[]; -extern struct constmap ofp_xm_t_map[]; -extern struct constmap ofp_config_map[]; -extern struct constmap ofp_controller_maxlen_map[]; -extern struct constmap ofp_instruction_t_map[]; -extern struct constmap ofp_portstate_map[]; -extern struct constmap ofp_portconfig_map[]; -extern struct constmap ofp_portmedia_map[]; -extern struct constmap ofp_pktin_reason_map[]; -extern struct constmap ofp_swcap_map[]; -extern struct constmap ofp_table_id_map[]; -extern struct constmap ofp_match_map[]; -extern struct constmap ofp_mp_t_map[]; -extern struct constmap ofp_action_map[]; -extern struct constmap ofp_flowcmd_map[]; -extern struct constmap ofp_flowflag_map[]; -extern struct constmap ofp_flowrem_reason_map[]; -extern struct constmap ofp_group_id_map[]; -extern struct constmap ofp_errtype_map[]; -extern struct constmap ofp_errflowmod_map[]; -extern struct constmap ofp_errmatch_map[]; -extern struct constmap ofp_errinst_map[]; -extern struct constmap ofp_errreq_map[]; -extern struct constmap ofp_table_featprop_map[]; - -#endif /* OFP_MAP_H */ diff --git a/usr.sbin/switchd/ofrelay.c b/usr.sbin/switchd/ofrelay.c deleted file mode 100644 index 653882caa4c..00000000000 --- a/usr.sbin/switchd/ofrelay.c +++ /dev/null @@ -1,447 +0,0 @@ -/* $OpenBSD: ofrelay.c,v 1.10 2016/12/22 15:31:43 rzalamena Exp $ */ - -/* - * Copyright (c) 2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" - -void ofrelay_close(struct switch_connection *); -void ofrelay_event(int, short, void *); -int ofrelay_input(int, short, void *); -int ofrelay_output(int, short, void *); -void ofrelay_accept(int, short, void *); -void ofrelay_inflight_dec(struct switch_connection *, const char *); - -void *ofrelay_input_open(struct switch_connection *, - struct ibuf *, ssize_t *); -ssize_t ofrelay_input_close(struct switch_connection *, - struct ibuf *, ssize_t); -int ofrelay_input_done(struct switch_connection *, struct ibuf *); -int ofrelay_bufget(struct switch_connection *, struct ibuf *); -void ofrelay_bufput(struct switch_connection *, struct ibuf *); - -volatile int ofrelay_sessions; -volatile int ofrelay_inflight; -static uint32_t ofrelay_conid; - -void -ofrelay(struct privsep *ps, struct privsep_proc *p) -{ - struct switchd *sc = ps->ps_env; - struct switch_server *srv = &sc->sc_server; - - log_info("listen on %s", print_host(&srv->srv_addr, NULL, 0)); - - if ((srv->srv_fd = switchd_listen((struct sockaddr *) - &srv->srv_addr)) == -1) - fatal("listen"); -} - -void -ofrelay_run(struct privsep *ps, struct privsep_proc *p, void *arg) -{ - struct switchd *sc = ps->ps_env; - struct switch_server *srv = &sc->sc_server; - - TAILQ_INIT(&sc->sc_conns); - TAILQ_INIT(&sc->sc_clients); - - srv->srv_sc = sc; - event_set(&srv->srv_ev, srv->srv_fd, EV_READ, ofrelay_accept, srv); - event_add(&srv->srv_ev, NULL); - evtimer_set(&srv->srv_evt, ofrelay_accept, srv); -} - -void -ofrelay_close(struct switch_connection *con) -{ - struct switchd *sc = con->con_sc; - struct switch_server *srv = con->con_srv; - - log_info("%s: connection %u.%u closed", __func__, - con->con_id, con->con_instance); - - if (event_initialized(&con->con_ev)) - event_del(&con->con_ev); - - TAILQ_REMOVE(&sc->sc_conns, con, con_entry); - ofrelay_sessions--; - - switch_freetables(con); - ofp_multipart_clear(con); - switch_remove(con->con_sc, con->con_switch); - msgbuf_clear(&con->con_wbuf); - ibuf_release(con->con_rbuf); - close(con->con_fd); - - ofrelay_inflight_dec(con, __func__); - - /* Some file descriptors are available again. */ - if (evtimer_pending(&srv->srv_evt, NULL)) { - DPRINTF("%s: accepting again", __func__); - evtimer_del(&srv->srv_evt); - event_add(&srv->srv_ev, NULL); - } - - free(con); -} - -void -ofrelay_event(int fd, short event, void *arg) -{ - struct switch_connection *con = arg; - const char *error = NULL; - - event_add(&con->con_ev, NULL); - if (event & EV_TIMEOUT) { - error = "timeout"; - goto fail; - } - if (event & EV_WRITE) { - if (ofrelay_output(fd, event, arg) == -1) { - error = "write"; - goto fail; - } - } - if (event & EV_READ) { - if (ofrelay_input(fd, event, arg) == -1) { - error = "input"; - goto fail; - } - } - - fail: - if (error != NULL) { - DPRINTF("%s: %s error", __func__, error); - ofrelay_close(con); - } -} - -int -ofrelay_input(int fd, short event, void *arg) -{ - struct switch_connection *con = arg; - struct ibuf *ibuf = con->con_rbuf; - ssize_t len, rlen; - size_t hlen; - void *buf; - struct ofp_header *oh = NULL; - - if ((buf = ofrelay_input_open(con, ibuf, &len)) == NULL) { - log_warn("%s: fd %d, failed to get buffer", __func__, fd); - return (-1); - } - - /* If we got a new buffer, read the complete openflow header first */ - if ((hlen = ibuf_length(ibuf)) < sizeof(struct ofp_header)) { - oh = (struct ofp_header *)ibuf_data(ibuf); - len = sizeof(*oh) - hlen; - } - - if ((rlen = read(fd, buf, len)) == -1) { - if (errno == EINTR || errno == EAGAIN) - return (0); - log_warn("%s: fd %d, failed to read", __func__, fd); - return (-1); - } - - print_hex(buf, 0, rlen); - - DPRINTF("%s: connection %u.%u read %zd bytes", __func__, - con->con_id, con->con_instance, rlen); - - if ((len = ofrelay_input_close(con, ibuf, rlen)) == -1) - return (-1); - else if (rlen == 0) { - /* connection closed */ - ofrelay_input_done(con, ibuf); - return (-1); - } - - /* After we verified the openflow header, set the size accordingly */ - if (oh != NULL && (hlen + rlen) == sizeof(*oh)) { - switch (oh->oh_version) { - case OFP_V_1_0: - case OFP_V_1_1: - case OFP_V_1_2: - case OFP_V_1_3: - break; - default: - DPRINTF("%s: fd %d, openflow version 0x%02x length %d" - " not supported", __func__, fd, oh->oh_version, - ntohs(oh->oh_length)); - return (-1); - } - - len = ntohs(oh->oh_length); - if (len == sizeof(*oh)) { - len = 0; - } else if (len > (ssize_t)ibuf->size) { - log_debug("%s: buffer too big: %zu > %zd", __func__, - len, ibuf->size); - return (-1); - } else - ibuf_setmax(ibuf, len); - } - - if (len > 0) - return (len); - - return (ofrelay_input_done(con, ibuf)); -} - -void -ofrelay_write(struct switch_connection *con, struct ibuf *buf) -{ - ibuf_close(&con->con_wbuf, buf); - - event_del(&con->con_ev); - event_set(&con->con_ev, con->con_fd, EV_READ|EV_WRITE, - ofrelay_event, con); - event_add(&con->con_ev, NULL); -} - -void * -ofrelay_input_open(struct switch_connection *con, - struct ibuf *buf, ssize_t *len) -{ - ssize_t left; - - left = buf->max - buf->wpos; - if (left == 0) { - ofrelay_bufget(con, buf); - left = buf->max; - } - if (len) - *len = left; - - return (buf->buf + buf->wpos); -} - -ssize_t -ofrelay_input_close(struct switch_connection *con, - struct ibuf *buf, ssize_t len) -{ - if (len <= 0) - return (0); - if (buf->wpos + len > buf->max) - return (-1); - buf->wpos += len; - - return (buf->max - buf->wpos); -} - -int -ofrelay_input_done(struct switch_connection *con, struct ibuf *buf) -{ - struct switch_control *sw; - - if (buf->wpos == 0) { - ofrelay_bufput(con, buf); - return (0); - } - - sw = con->con_switch; - log_debug("%s: connection %u.%u: %ld bytes from switch %u", __func__, - con->con_id, con->con_instance, buf->wpos, - sw == NULL ? 0 : sw->sw_id); - - print_hex(buf->buf, 0, buf->wpos); - - if (ofp_input(con, buf) == -1) - return (-1); - - /* Update read buffer */ - if (ofrelay_bufget(con, buf) == -1) - return (-1); - - return (0); -} - -int -ofrelay_bufget(struct switch_connection *con, struct ibuf *buf) -{ - ibuf_reset(buf); - - /* Should be a static buffer with maximum size */ - if (ibuf_setmax(buf, SWITCHD_MSGBUF_MAX) == -1) - fatalx("%s: invalid buffer", __func__); - - return (0); -} - -void -ofrelay_bufput(struct switch_connection *con, struct ibuf *buf) -{ - /* Just reset the buffer */ - ofrelay_bufget(con, buf); -} - -int -ofrelay_output(int fd, short event, void *arg) -{ - struct switch_connection *con = arg; - struct msgbuf *wbuf = &con->con_wbuf; - - if (!wbuf->queued) { - event_del(&con->con_ev); - event_set(&con->con_ev, con->con_fd, EV_READ, - ofrelay_event, con); - event_add(&con->con_ev, NULL); - return (0); - } - - if (ibuf_write(wbuf) <= 0 && errno != EAGAIN) - return (-1); - - return (0); -} - -void -ofrelay_accept(int fd, short event, void *arg) -{ - struct switch_server *srv = arg; - struct sockaddr_storage ss; - int s; - socklen_t slen; - - event_add(&srv->srv_ev, NULL); - if (event & EV_TIMEOUT) - return; - - slen = sizeof(ss); - if ((s = accept4_reserve(fd, (struct sockaddr *)&ss, &slen, - SOCK_NONBLOCK|SOCK_CLOEXEC, SWITCHD_FD_RESERVE, - &ofrelay_inflight)) == -1) { - /* - * Pause accept if we are out of file descriptors, or - * libevent will haunt us here too. - */ - if (errno == ENFILE || errno == EMFILE) { - struct timeval evtpause = { 1, 0 }; - - event_del(&srv->srv_ev); - evtimer_add(&srv->srv_evt, &evtpause); - log_warn("%s: deferring connections", __func__); - } else - log_warn("%s accept", __func__); - return; - } - ss.ss_len = slen; - - (void)ofrelay_attach(srv, s, (struct sockaddr *)&ss); -} - -void -ofrelay_inflight_dec(struct switch_connection *con, const char *why) -{ - if (con != NULL) { - /* the flight already left inflight mode. */ - if (con->con_inflight == 0) - return; - con->con_inflight = 0; - } - - /* the file was never opened, thus this was an inflight client. */ - ofrelay_inflight--; - DPRINTF("%s: inflight decremented, now %d, %s", - __func__, ofrelay_inflight, why); -} - -int -ofrelay_attach(struct switch_server *srv, int s, struct sockaddr *sa) -{ - struct switchd *sc = srv->srv_sc; - struct privsep *ps = &sc->sc_ps; - struct switch_connection *con = NULL; - socklen_t slen; - int ret = -1; - - if (ofrelay_sessions >= SWITCHD_MAX_SESSIONS) { - log_warn("too many sessions"); - goto done; - } - - if ((con = calloc(1, sizeof(*con))) == NULL) { - log_warn("calloc"); - goto done; - } - - con->con_fd = s; - con->con_inflight = 1; - con->con_sc = sc; - con->con_id = ++ofrelay_conid; - con->con_instance = ps->ps_instance + 1; - con->con_srv = srv; - con->con_state = OFP_STATE_CLOSED; - SLIST_INIT(&con->con_mmlist); - TAILQ_INIT(&con->con_stlist); - - memcpy(&con->con_peer, sa, sa->sa_len); - con->con_port = htons(socket_getport(&con->con_peer)); - - if (getsockname(s, (struct sockaddr *)&con->con_local, &slen) == -1) { - /* Set local sockaddr to AF_UNSPEC */ - memset(&con->con_local, 0, sizeof(con->con_local)); - } - - log_info("%s: new connection %u.%u", - __func__, con->con_id, con->con_instance); - - ofrelay_sessions++; - TAILQ_INSERT_TAIL(&sc->sc_conns, con, con_entry); - - if ((con->con_rbuf = ibuf_static()) == NULL || - ofrelay_bufget(con, con->con_rbuf) == -1) { - log_warn("ibuf"); - goto done; - } - msgbuf_init(&con->con_wbuf); - con->con_wbuf.fd = s; - - memset(&con->con_ev, 0, sizeof(con->con_ev)); - event_set(&con->con_ev, con->con_fd, EV_READ, ofrelay_event, con); - event_add(&con->con_ev, NULL); - - ret = ofp_open(ps, con); - - done: - if (con == NULL) - close(s); - ofrelay_inflight_dec(con, __func__); - if (ret != 0) - ofrelay_close(con); - - return (ret); -} diff --git a/usr.sbin/switchd/packet.c b/usr.sbin/switchd/packet.c deleted file mode 100644 index ce93d6f23a8..00000000000 --- a/usr.sbin/switchd/packet.c +++ /dev/null @@ -1,102 +0,0 @@ -/* $OpenBSD: packet.c,v 1.6 2019/05/05 21:33:00 akoshibe Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "switchd.h" - -const uint8_t etherbroadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -const uint8_t etherzeroaddr[] = { 0, 0, 0, 0, 0, 0 }; - -int packet_ether_unicast(uint8_t *); - -int -packet_ether_unicast(uint8_t *ea) -{ - if (memcmp(ea, etherbroadcastaddr, ETHER_ADDR_LEN) == 0 || - memcmp(ea, etherzeroaddr, ETHER_ADDR_LEN) == 0 || - ETHER_IS_MULTICAST(ea)) - return (-1); - return (0); -} - -int -packet_ether_input(struct ibuf *ibuf, size_t len, struct packet *pkt) -{ - struct ether_header *eh; - - if (len < sizeof(*eh)) - return (-1); - - pkt->pkt_len = ibuf_dataleft(ibuf); - if ((eh = ibuf_getdata(ibuf, sizeof(*eh))) == NULL) { - log_debug("short packet"); - return (-1); - } - - pkt->pkt_eh = eh; - pkt->pkt_buf = (uint8_t *)eh; - - return (0); -} - -int -packet_input(struct switchd *sc, struct switch_control *sw, uint32_t srcport, - uint32_t *dstport, struct packet *pkt) -{ - struct ether_header *eh; - struct macaddr *src, *dst; - - if (sw == NULL) - return (-1); - - eh = pkt->pkt_eh; - if ((packet_ether_unicast(eh->ether_shost) == -1) || - (src = switch_learn(sc, sw, eh->ether_shost, srcport)) == NULL) - return (-1); - - if (packet_ether_unicast(eh->ether_dhost) == -1) - dst = NULL; - else - dst = switch_cached(sw, eh->ether_dhost); - - log_debug("%s: %s -> %s, port %u -> %u", __func__, - print_ether(eh->ether_shost), - print_ether(eh->ether_dhost), - src->mac_port, - dst == NULL ? OFP_PORT_ANY : dst->mac_port); - - if (dstport) - *dstport = dst == NULL ? OFP_PORT_ANY : dst->mac_port; - - return (0); -} diff --git a/usr.sbin/switchd/parse.y b/usr.sbin/switchd/parse.y deleted file mode 100644 index a77d3fd2da3..00000000000 --- a/usr.sbin/switchd/parse.y +++ /dev/null @@ -1,763 +0,0 @@ -/* $OpenBSD: parse.y,v 1.16 2021/10/15 15:01:29 naddy Exp $ */ - -/* - * Copyright (c) 2007-2016 Reyk Floeter - * Copyright (c) 2004, 2005 Esben Norby - * Copyright (c) 2004 Ryan McBride - * Copyright (c) 2002, 2003, 2004 Henning Brauer - * Copyright (c) 2001 Markus Friedl. All rights reserved. - * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. - * Copyright (c) 2001 Theo de Raadt. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -%{ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" - -TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -static struct file { - TAILQ_ENTRY(file) entry; - FILE *stream; - char *name; - size_t ungetpos; - size_t ungetsize; - u_char *ungetbuf; - int eof_reached; - int lineno; - int errors; -} *file, *topfile; -struct file *pushfile(const char *, int); -int popfile(void); -int yyparse(void); -int yylex(void); -int yyerror(const char *, ...) - __attribute__((__format__ (printf, 1, 2))) - __attribute__((__nonnull__ (1))); -int kw_cmp(const void *, const void *); -int lookup(char *); -int igetc(void); -int lgetc(int); -void lungetc(int); -int findeol(void); -int host(const char *, struct sockaddr *, socklen_t); - -struct switchd *conf; - -TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -struct sym { - TAILQ_ENTRY(sym) entry; - int used; - int persist; - char *nam; - char *val; -}; -int symset(const char *, const char *, int); -char *symget(const char *); - -typedef struct { - union { - int64_t number; - char *string; - in_port_t port; - struct switch_client - *conn; - } v; - int lineno; -} YYSTYPE; - -%} - -%token INCLUDE ERROR LISTEN ON TLS PORT DEVICE FORWARD TO -%token STRING -%token NUMBER -%type opttls -%type optofcconn -%type port - -%% - -grammar : /* empty */ - | grammar '\n' - | grammar include '\n' - | grammar listen '\n' - | grammar device '\n' - | grammar varset '\n' - | grammar error '\n' { file->errors++; } - ; - -include : INCLUDE STRING { - struct file *nfile; - - if ((nfile = pushfile($2, 0)) == NULL) { - yyerror("failed to include file %s", $2); - free($2); - YYERROR; - } - free($2); - - file = nfile; - lungetc('\n'); - } - ; - -listen : LISTEN ON STRING opttls port { - if (host($3, - (struct sockaddr *)&conf->sc_server.srv_addr, - sizeof(conf->sc_server.srv_addr)) != 0) { - free($3); - YYERROR; - } - free($3); - conf->sc_server.srv_tls = $4; - ((struct sockaddr_in *)&conf->sc_server.srv_addr) - ->sin_port = $5; - } - | LISTEN ON STRING opttls { - if (host($3, - (struct sockaddr *)&conf->sc_server.srv_addr, - sizeof(conf->sc_server.srv_addr)) != 0) { - free($3); - YYERROR; - } - free($3); - conf->sc_server.srv_tls = $4; - ((struct sockaddr_in *)&conf->sc_server.srv_addr) - ->sin_port = htons(SWITCHD_CTLR_PORT); - } - ; - -port : PORT NUMBER { - if ($2 <= 0 || $2 > (int)USHRT_MAX) { - yyerror("invalid port: %lld", $2); - YYERROR; - } - $$ = htons($2); - } - ; - -opttls : /* empty */ { $$ = 0; } - | TLS { $$ = 1; } - ; - -device : DEVICE STRING optofcconn { - struct switch_client *c; - struct switch_address s; - struct sockaddr_un *un; - - memset(&s, 0, sizeof(s)); - un = (struct sockaddr_un *)&s.swa_addr; - - if (*$2 != '/') { - yyerror("not an absolute path: %s", $2); - free($2); - YYERROR; - } - - un->sun_family = AF_LOCAL; - un->sun_len = sizeof(*un); - if (strlcpy(un->sun_path, $2, - sizeof(un->sun_path)) >= sizeof(un->sun_path)) { - yyerror("device name is too long: %s", $2); - free($2); - YYERROR; - } - free($2); - - TAILQ_FOREACH(c, &conf->sc_clients, swc_next) { - if (sockaddr_cmp((struct sockaddr *) - &c->swc_addr.swa_addr, - (struct sockaddr *)&s.swa_addr, -1) == 0) - break; - } - if (c != NULL) { - yyerror("device name is duplicated"); - YYERROR; - } - - memcpy(&$3->swc_addr, &s, sizeof(s)); - - TAILQ_INSERT_TAIL(&conf->sc_clients, $3, swc_next); - } - ; - -optofcconn : /* empty */ { - if (($$ = calloc(1, - sizeof(struct switch_client))) == NULL) - fatal("calloc"); - $$->swc_addr.swa_type = $$->swc_target.swa_type = - SWITCH_CONN_LOCAL; - } - | FORWARD TO STRING { - size_t len; - - if (($$ = calloc(1, - sizeof(struct switch_client))) == NULL) - fatal("calloc"); - len = 4; - if (strncmp($3, "tcp:", len) == 0) - $$->swc_target.swa_type = SWITCH_CONN_TCP; - else if (strncmp($3, "tls:", len) == 0) - $$->swc_target.swa_type = SWITCH_CONN_TLS; - else { - len = 0; - $$->swc_target.swa_type = SWITCH_CONN_TCP; - } - if (parsehostport($3 + len, - (struct sockaddr *)&$$->swc_target.swa_addr, - sizeof($$->swc_target.swa_addr)) == -1) { - yyerror("could not parse host and port part " - "of forward target"); - free($$); - free($3); - YYERROR; - } - free($3); - } - ; - -varset : STRING '=' STRING { - if (symset($1, $3, 0) == -1) - fatal("cannot store variable"); - free($1); - free($3); - } - ; - -%% - -struct keywords { - const char *k_name; - int k_val; -}; - -int -yyerror(const char *fmt, ...) -{ - va_list ap; - char *msg; - - file->errors++; - va_start(ap, fmt); - if (vasprintf(&msg, fmt, ap) == -1) - fatal("yyerror vasprintf"); - va_end(ap); - log_warnx("%s:%d: %s", file->name, yylval.lineno, msg); - free(msg); - return (0); -} - -int -kw_cmp(const void *k, const void *e) -{ - return (strcmp(k, ((const struct keywords *)e)->k_name)); -} - -int -lookup(char *s) -{ - /* this has to be sorted always */ - static const struct keywords keywords[] = { - { "device", DEVICE }, - { "forward", FORWARD }, - { "include", INCLUDE }, - { "listen", LISTEN }, - { "on", ON }, - { "port", PORT }, - { "tls", TLS }, - { "to", TO }, - }; - const struct keywords *p; - - p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), - sizeof(keywords[0]), kw_cmp); - - if (p) - return (p->k_val); - else - return (STRING); -} - -#define START_EXPAND 1 -#define DONE_EXPAND 2 - -static int expanding; - -int -igetc(void) -{ - int c; - - while (1) { - if (file->ungetpos > 0) - c = file->ungetbuf[--file->ungetpos]; - else - c = getc(file->stream); - - if (c == START_EXPAND) - expanding = 1; - else if (c == DONE_EXPAND) - expanding = 0; - else - break; - } - return (c); -} - -int -lgetc(int quotec) -{ - int c, next; - - if (quotec) { - if ((c = igetc()) == EOF) { - yyerror("reached end of file while parsing " - "quoted string"); - if (file == topfile || popfile() == EOF) - return (EOF); - return (quotec); - } - return (c); - } - - while ((c = igetc()) == '\\') { - next = igetc(); - if (next != '\n') { - c = next; - break; - } - yylval.lineno = file->lineno; - file->lineno++; - } - if (c == '\t' || c == ' ') { - /* Compress blanks to a single space. */ - do { - c = getc(file->stream); - } while (c == '\t' || c == ' '); - ungetc(c, file->stream); - c = ' '; - } - - if (c == EOF) { - /* - * Fake EOL when hit EOF for the first time. This gets line - * count right if last line in included file is syntactically - * invalid and has no newline. - */ - if (file->eof_reached == 0) { - file->eof_reached = 1; - return ('\n'); - } - while (c == EOF) { - if (file == topfile || popfile() == EOF) - return (EOF); - c = igetc(); - } - } - return (c); -} - -void -lungetc(int c) -{ - if (c == EOF) - return; - - if (file->ungetpos >= file->ungetsize) { - void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); - if (p == NULL) - err(1, "%s", __func__); - file->ungetbuf = p; - file->ungetsize *= 2; - } - file->ungetbuf[file->ungetpos++] = c; -} - -int -findeol(void) -{ - int c; - - /* skip to either EOF or the first real EOL */ - while (1) { - c = lgetc(0); - if (c == '\n') { - file->lineno++; - break; - } - if (c == EOF) - break; - } - return (ERROR); -} - -int -yylex(void) -{ - char buf[8096]; - char *p, *val; - int quotec, next, c; - int token; - -top: - p = buf; - while ((c = lgetc(0)) == ' ' || c == '\t') - ; /* nothing */ - - yylval.lineno = file->lineno; - if (c == '#') - while ((c = lgetc(0)) != '\n' && c != EOF) - ; /* nothing */ - if (c == '$' && !expanding) { - while (1) { - if ((c = lgetc(0)) == EOF) - return (0); - - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - if (isalnum(c) || c == '_') { - *p++ = c; - continue; - } - *p = '\0'; - lungetc(c); - break; - } - val = symget(buf); - if (val == NULL) { - yyerror("macro '%s' not defined", buf); - return (findeol()); - } - p = val + strlen(val) - 1; - lungetc(DONE_EXPAND); - while (p >= val) { - lungetc((unsigned char)*p); - p--; - } - lungetc(START_EXPAND); - goto top; - } - - switch (c) { - case '\'': - case '"': - quotec = c; - while (1) { - if ((c = lgetc(quotec)) == EOF) - return (0); - if (c == '\n') { - file->lineno++; - continue; - } else if (c == '\\') { - if ((next = lgetc(quotec)) == EOF) - return (0); - if (next == quotec || next == ' ' || - next == '\t') - c = next; - else if (next == '\n') { - file->lineno++; - continue; - } else - lungetc(next); - } else if (c == quotec) { - *p = '\0'; - break; - } else if (c == '\0') { - yyerror("syntax error"); - return (findeol()); - } - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - *p++ = c; - } - yylval.v.string = strdup(buf); - if (yylval.v.string == NULL) - fatal("yylex: strdup"); - return (STRING); - } - -#define allowed_to_end_number(x) \ - (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') - - if (c == '-' || isdigit(c)) { - do { - *p++ = c; - if ((size_t)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && isdigit(c)); - lungetc(c); - if (p == buf + 1 && buf[0] == '-') - goto nodigits; - if (c == EOF || allowed_to_end_number(c)) { - const char *errstr = NULL; - - *p = '\0'; - yylval.v.number = strtonum(buf, LLONG_MIN, - LLONG_MAX, &errstr); - if (errstr) { - yyerror("\"%s\" invalid number: %s", - buf, errstr); - return (findeol()); - } - return (NUMBER); - } else { -nodigits: - while (p > buf + 1) - lungetc((unsigned char)*--p); - c = (unsigned char)*--p; - if (c == '-') - return (c); - } - } - -#define allowed_in_string(x) \ - (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ - x != '{' && x != '}' && \ - x != '!' && x != '=' && x != '#' && \ - x != ',')) - - if (isalnum(c) || c == ':' || c == '_' || c == '/') { - do { - *p++ = c; - if ((size_t)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); - lungetc(c); - *p = '\0'; - if ((token = lookup(buf)) == STRING) - if ((yylval.v.string = strdup(buf)) == NULL) - fatal("yylex: strdup"); - return (token); - } - if (c == '\n') { - yylval.lineno = file->lineno; - file->lineno++; - } - if (c == EOF) - return (0); - return (c); -} - -struct file * -pushfile(const char *name, int secret) -{ - struct file *nfile; - - if ((nfile = calloc(1, sizeof(struct file))) == NULL) { - log_warn("%s", __func__); - return (NULL); - } - if ((nfile->name = strdup(name)) == NULL) { - log_warn("%s", __func__); - free(nfile); - return (NULL); - } - if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { - free(nfile->name); - free(nfile); - return (NULL); - } - nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; - nfile->ungetsize = 16; - nfile->ungetbuf = malloc(nfile->ungetsize); - if (nfile->ungetbuf == NULL) { - log_warn("%s", __func__); - fclose(nfile->stream); - free(nfile->name); - free(nfile); - return (NULL); - } - TAILQ_INSERT_TAIL(&files, nfile, entry); - return (nfile); -} - -int -popfile(void) -{ - struct file *prev; - - if ((prev = TAILQ_PREV(file, files, entry)) != NULL) - prev->errors += file->errors; - - TAILQ_REMOVE(&files, file, entry); - fclose(file->stream); - free(file->name); - free(file->ungetbuf); - free(file); - file = prev; - return (file ? 0 : EOF); -} - -int -parse_config(const char *filename, struct switchd *sc) -{ - struct sym *sym; - int errors = 0; - struct sockaddr_in *sin4; - - conf = sc; - - /* Set the default 0.0.0.0 6653/tcp */ - memset(&conf->sc_server.srv_addr, 0, sizeof(conf->sc_server.srv_addr)); - sin4 = (struct sockaddr_in *)&conf->sc_server.srv_addr; - sin4->sin_family = AF_INET; - sin4->sin_port = htons(SWITCHD_CTLR_PORT); - sin4->sin_len = sizeof(struct sockaddr_in); - - if ((file = pushfile(filename, 0)) == NULL) { - log_warn("failed to open %s", filename); - return (-1); - } - topfile = file; - setservent(1); - - yyparse(); - errors = file->errors; - popfile(); - - endservent(); - - /* Free macros and check which have not been used. */ - while ((sym = TAILQ_FIRST(&symhead))) { - if (!sym->used) - log_debug("warning: macro '%s' not " - "used\n", sym->nam); - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - - return (errors ? -1 : 0); -} - -int -symset(const char *nam, const char *val, int persist) -{ - struct sym *sym; - - TAILQ_FOREACH(sym, &symhead, entry) { - if (strcmp(nam, sym->nam) == 0) - break; - } - - if (sym != NULL) { - if (sym->persist == 1) - return (0); - else { - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - } - if ((sym = calloc(1, sizeof(*sym))) == NULL) - return (-1); - - sym->nam = strdup(nam); - if (sym->nam == NULL) { - free(sym); - return (-1); - } - sym->val = strdup(val); - if (sym->val == NULL) { - free(sym->nam); - free(sym); - return (-1); - } - sym->used = 0; - sym->persist = persist; - TAILQ_INSERT_TAIL(&symhead, sym, entry); - return (0); -} - -int -cmdline_symset(char *s) -{ - char *sym, *val; - int ret; - - if ((val = strrchr(s, '=')) == NULL) - return (-1); - sym = strndup(s, val - s); - if (sym == NULL) - fatal("%s: strndup", __func__); - ret = symset(sym, val + 1, 1); - free(sym); - - return (ret); -} - -char * -symget(const char *nam) -{ - struct sym *sym; - - TAILQ_FOREACH(sym, &symhead, entry) { - if (strcmp(nam, sym->nam) == 0) { - sym->used = 1; - return (sym->val); - } - } - return (NULL); -} - -int -host(const char *str, struct sockaddr *sa, socklen_t salen) -{ - struct addrinfo hints, *ai0; - int error; - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_NUMERICHOST; - hints.ai_family = AF_UNSPEC; - - if ((error = getaddrinfo(str, NULL, &hints, &ai0)) != 0) { - yyerror("invalid listen address: %s: %s", str, - gai_strerror(error)); - return (-1); - } - if (salen >= ai0->ai_addrlen) - memcpy(sa, ai0->ai_addr, ai0->ai_addrlen); - else { - yyerror("addrlen is invalid: %d", (int)ai0->ai_addrlen); - freeaddrinfo(ai0); - return (-1); - } - freeaddrinfo(ai0); - - return (0); -} diff --git a/usr.sbin/switchd/proc.c b/usr.sbin/switchd/proc.c deleted file mode 100644 index 6f6a87f5095..00000000000 --- a/usr.sbin/switchd/proc.c +++ /dev/null @@ -1,849 +0,0 @@ -/* $OpenBSD: proc.c,v 1.15 2021/04/20 21:11:56 dv Exp $ */ - -/* - * Copyright (c) 2010 - 2016 Reyk Floeter - * Copyright (c) 2008 Pierre-Yves Ritschard - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "proc.h" - -void proc_exec(struct privsep *, struct privsep_proc *, unsigned int, int, - int, char **); -void proc_setup(struct privsep *, struct privsep_proc *, unsigned int); -void proc_open(struct privsep *, int, int); -void proc_accept(struct privsep *, int, enum privsep_procid, - unsigned int); -void proc_close(struct privsep *); -int proc_ispeer(struct privsep_proc *, unsigned int, enum privsep_procid); -void proc_shutdown(struct privsep_proc *); -void proc_sig_handler(int, short, void *); -void proc_range(struct privsep *, enum privsep_procid, int *, int *); -int proc_dispatch_null(int, struct privsep_proc *, struct imsg *); - -int -proc_ispeer(struct privsep_proc *procs, unsigned int nproc, - enum privsep_procid type) -{ - unsigned int i; - - for (i = 0; i < nproc; i++) - if (procs[i].p_id == type) - return (1); - return (0); -} - -enum privsep_procid -proc_getid(struct privsep_proc *procs, unsigned int nproc, - const char *proc_name) -{ - struct privsep_proc *p; - unsigned int proc; - - for (proc = 0; proc < nproc; proc++) { - p = &procs[proc]; - if (strcmp(p->p_title, proc_name)) - continue; - - return (p->p_id); - } - - return (PROC_MAX); -} - -void -proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, - int debug, int argc, char **argv) -{ - unsigned int proc, nargc, i, proc_i; - char **nargv; - struct privsep_proc *p; - char num[32]; - int fd; - - /* Prepare the new process argv. */ - nargv = calloc(argc + 5, sizeof(char *)); - if (nargv == NULL) - fatal("%s: calloc", __func__); - - /* Copy call argument first. */ - nargc = 0; - nargv[nargc++] = argv[0]; - - /* Set process name argument and save the position. */ - nargv[nargc++] = "-P"; - proc_i = nargc; - nargc++; - - /* Point process instance arg to stack and copy the original args. */ - nargv[nargc++] = "-I"; - nargv[nargc++] = num; - for (i = 1; i < (unsigned int) argc; i++) - nargv[nargc++] = argv[i]; - - nargv[nargc] = NULL; - - for (proc = 0; proc < nproc; proc++) { - p = &procs[proc]; - - /* Update args with process title. */ - nargv[proc_i] = (char *)(uintptr_t)p->p_title; - - /* Fire children processes. */ - for (i = 0; i < ps->ps_instances[p->p_id]; i++) { - /* Update the process instance number. */ - snprintf(num, sizeof(num), "%u", i); - - fd = ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0]; - ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0] = -1; - - switch (fork()) { - case -1: - fatal("%s: fork", __func__); - break; - case 0: - /* First create a new session */ - if (setsid() == -1) - fatal("setsid"); - - /* Prepare parent socket. */ - if (fd != PROC_PARENT_SOCK_FILENO) { - if (dup2(fd, PROC_PARENT_SOCK_FILENO) - == -1) - fatal("dup2"); - } else if (fcntl(fd, F_SETFD, 0) == -1) - fatal("fcntl"); - - /* Daemons detach from terminal. */ - if (!debug && (fd = - open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { - (void)dup2(fd, STDIN_FILENO); - (void)dup2(fd, STDOUT_FILENO); - (void)dup2(fd, STDERR_FILENO); - if (fd > 2) - (void)close(fd); - } - - execvp(argv[0], nargv); - fatal("%s: execvp", __func__); - break; - default: - /* Close child end. */ - close(fd); - break; - } - } - } - free(nargv); -} - -void -proc_connect(struct privsep *ps) -{ - struct imsgev *iev; - unsigned int src, dst, inst; - - /* Don't distribute any sockets if we are not really going to run. */ - if (ps->ps_noaction) - return; - - for (dst = 0; dst < PROC_MAX; dst++) { - /* We don't communicate with ourselves. */ - if (dst == PROC_PARENT) - continue; - - for (inst = 0; inst < ps->ps_instances[dst]; inst++) { - iev = &ps->ps_ievs[dst][inst]; - imsg_init(&iev->ibuf, ps->ps_pp->pp_pipes[dst][inst]); - event_set(&iev->ev, iev->ibuf.fd, iev->events, - iev->handler, iev->data); - event_add(&iev->ev, NULL); - } - } - - /* Distribute the socketpair()s for everyone. */ - for (src = 0; src < PROC_MAX; src++) - for (dst = src; dst < PROC_MAX; dst++) { - /* Parent already distributed its fds. */ - if (src == PROC_PARENT || dst == PROC_PARENT) - continue; - - proc_open(ps, src, dst); - } -} - -void -proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, - int debug, int argc, char **argv, enum privsep_procid proc_id) -{ - struct privsep_proc *p = NULL; - struct privsep_pipes *pa, *pb; - unsigned int proc; - unsigned int dst; - int fds[2]; - - /* Don't initiate anything if we are not really going to run. */ - if (ps->ps_noaction) - return; - - if (proc_id == PROC_PARENT) { - privsep_process = PROC_PARENT; - proc_setup(ps, procs, nproc); - - /* - * Create the children sockets so we can use them - * to distribute the rest of the socketpair()s using - * proc_connect() later. - */ - for (dst = 0; dst < PROC_MAX; dst++) { - /* Don't create socket for ourselves. */ - if (dst == PROC_PARENT) - continue; - - for (proc = 0; proc < ps->ps_instances[dst]; proc++) { - pa = &ps->ps_pipes[PROC_PARENT][0]; - pb = &ps->ps_pipes[dst][proc]; - if (socketpair(AF_UNIX, - SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, - PF_UNSPEC, fds) == -1) - fatal("%s: socketpair", __func__); - - pa->pp_pipes[dst][proc] = fds[0]; - pb->pp_pipes[PROC_PARENT][0] = fds[1]; - } - } - - /* Engage! */ - proc_exec(ps, procs, nproc, debug, argc, argv); - return; - } - - /* Initialize a child */ - for (proc = 0; proc < nproc; proc++) { - if (procs[proc].p_id != proc_id) - continue; - p = &procs[proc]; - break; - } - if (p == NULL || p->p_init == NULL) - fatalx("%s: process %d missing process initialization", - __func__, proc_id); - - p->p_init(ps, p); - - fatalx("failed to initiate child process"); -} - -void -proc_accept(struct privsep *ps, int fd, enum privsep_procid dst, - unsigned int n) -{ - struct privsep_pipes *pp = ps->ps_pp; - struct imsgev *iev; - - if (ps->ps_ievs[dst] == NULL) { -#if DEBUG > 1 - log_debug("%s: %s src %d %d to dst %d %d not connected", - __func__, ps->ps_title[privsep_process], - privsep_process, ps->ps_instance + 1, - dst, n + 1); -#endif - close(fd); - return; - } - - if (pp->pp_pipes[dst][n] != -1) { - log_warnx("%s: duplicated descriptor", __func__); - close(fd); - return; - } else - pp->pp_pipes[dst][n] = fd; - - iev = &ps->ps_ievs[dst][n]; - imsg_init(&iev->ibuf, fd); - event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); - event_add(&iev->ev, NULL); -} - -void -proc_setup(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc) -{ - unsigned int i, j, src, dst, id; - struct privsep_pipes *pp; - - /* Initialize parent title, ps_instances and procs. */ - ps->ps_title[PROC_PARENT] = "parent"; - - for (src = 0; src < PROC_MAX; src++) - /* Default to 1 process instance */ - if (ps->ps_instances[src] < 1) - ps->ps_instances[src] = 1; - - for (src = 0; src < nproc; src++) { - procs[src].p_ps = ps; - if (procs[src].p_cb == NULL) - procs[src].p_cb = proc_dispatch_null; - - id = procs[src].p_id; - ps->ps_title[id] = procs[src].p_title; - if ((ps->ps_ievs[id] = calloc(ps->ps_instances[id], - sizeof(struct imsgev))) == NULL) - fatal("%s: calloc", __func__); - - /* With this set up, we are ready to call imsg_init(). */ - for (i = 0; i < ps->ps_instances[id]; i++) { - ps->ps_ievs[id][i].handler = proc_dispatch; - ps->ps_ievs[id][i].events = EV_READ; - ps->ps_ievs[id][i].proc = &procs[src]; - ps->ps_ievs[id][i].data = &ps->ps_ievs[id][i]; - } - } - - /* - * Allocate pipes for all process instances (incl. parent) - * - * - ps->ps_pipes: N:M mapping - * N source processes connected to M destination processes: - * [src][instances][dst][instances], for example - * [PROC_RELAY][3][PROC_CA][3] - * - * - ps->ps_pp: per-process 1:M part of ps->ps_pipes - * Each process instance has a destination array of socketpair fds: - * [dst][instances], for example - * [PROC_PARENT][0] - */ - for (src = 0; src < PROC_MAX; src++) { - /* Allocate destination array for each process */ - if ((ps->ps_pipes[src] = calloc(ps->ps_instances[src], - sizeof(struct privsep_pipes))) == NULL) - fatal("%s: calloc", __func__); - - for (i = 0; i < ps->ps_instances[src]; i++) { - pp = &ps->ps_pipes[src][i]; - - for (dst = 0; dst < PROC_MAX; dst++) { - /* Allocate maximum fd integers */ - if ((pp->pp_pipes[dst] = - calloc(ps->ps_instances[dst], - sizeof(int))) == NULL) - fatal("%s: calloc", __func__); - - /* Mark fd as unused */ - for (j = 0; j < ps->ps_instances[dst]; j++) - pp->pp_pipes[dst][j] = -1; - } - } - } - - ps->ps_pp = &ps->ps_pipes[privsep_process][ps->ps_instance]; -} - -void -proc_kill(struct privsep *ps) -{ - char *cause; - pid_t pid; - int len, status; - - if (privsep_process != PROC_PARENT) - return; - - proc_close(ps); - - do { - pid = waitpid(WAIT_ANY, &status, 0); - if (pid <= 0) - continue; - - if (WIFSIGNALED(status)) { - len = asprintf(&cause, "terminated; signal %d", - WTERMSIG(status)); - } else if (WIFEXITED(status)) { - if (WEXITSTATUS(status) != 0) - len = asprintf(&cause, "exited abnormally"); - else - len = 0; - } else - len = -1; - - if (len == 0) { - /* child exited OK, don't print a warning message */ - } else if (len != -1) { - log_warnx("lost child: pid %u %s", pid, cause); - free(cause); - } else - log_warnx("lost child: pid %u", pid); - } while (pid != -1 || (pid == -1 && errno == EINTR)); -} - -void -proc_open(struct privsep *ps, int src, int dst) -{ - struct privsep_pipes *pa, *pb; - struct privsep_fd pf; - int fds[2]; - unsigned int i, j; - - /* Exchange pipes between process. */ - for (i = 0; i < ps->ps_instances[src]; i++) { - for (j = 0; j < ps->ps_instances[dst]; j++) { - /* Don't create sockets for ourself. */ - if (src == dst && i == j) - continue; - - pa = &ps->ps_pipes[src][i]; - pb = &ps->ps_pipes[dst][j]; - if (socketpair(AF_UNIX, - SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, - PF_UNSPEC, fds) == -1) - fatal("%s: socketpair", __func__); - - pa->pp_pipes[dst][j] = fds[0]; - pb->pp_pipes[src][i] = fds[1]; - - pf.pf_procid = src; - pf.pf_instance = i; - if (proc_compose_imsg(ps, dst, j, IMSG_CTL_PROCFD, - -1, pb->pp_pipes[src][i], &pf, sizeof(pf)) == -1) - fatal("%s: proc_compose_imsg", __func__); - - pf.pf_procid = dst; - pf.pf_instance = j; - if (proc_compose_imsg(ps, src, i, IMSG_CTL_PROCFD, - -1, pa->pp_pipes[dst][j], &pf, sizeof(pf)) == -1) - fatal("%s: proc_compose_imsg", __func__); - - /* - * We have to flush to send the descriptors and close - * them to avoid the fd ramp on startup. - */ - if (proc_flush_imsg(ps, src, i) == -1 || - proc_flush_imsg(ps, dst, j) == -1) - fatal("%s: imsg_flush", __func__); - } - } -} - -void -proc_close(struct privsep *ps) -{ - unsigned int dst, n; - struct privsep_pipes *pp; - - if (ps == NULL) - return; - - pp = ps->ps_pp; - - for (dst = 0; dst < PROC_MAX; dst++) { - if (ps->ps_ievs[dst] == NULL) - continue; - - for (n = 0; n < ps->ps_instances[dst]; n++) { - if (pp->pp_pipes[dst][n] == -1) - continue; - - /* Cancel the fd, close and invalidate the fd */ - event_del(&(ps->ps_ievs[dst][n].ev)); - imsg_clear(&(ps->ps_ievs[dst][n].ibuf)); - close(pp->pp_pipes[dst][n]); - pp->pp_pipes[dst][n] = -1; - } - free(ps->ps_ievs[dst]); - } -} - -void -proc_shutdown(struct privsep_proc *p) -{ - struct privsep *ps = p->p_ps; - - if (p->p_shutdown != NULL) - (*p->p_shutdown)(); - - proc_close(ps); - - log_info("%s exiting, pid %d", p->p_title, getpid()); - - exit(0); -} - -void -proc_sig_handler(int sig, short event, void *arg) -{ - struct privsep_proc *p = arg; - - switch (sig) { - case SIGINT: - case SIGTERM: - proc_shutdown(p); - break; - case SIGCHLD: - case SIGHUP: - case SIGPIPE: - case SIGUSR1: - /* ignore */ - break; - default: - fatalx("%s: unexpected signal", __func__); - /* NOTREACHED */ - } -} - -void -proc_run(struct privsep *ps, struct privsep_proc *p, - struct privsep_proc *procs, unsigned int nproc, - void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg) -{ - struct passwd *pw; - const char *root; - struct control_sock *rcs; - - log_procinit(p->p_title); - - /* Set the process group of the current process */ - setpgid(0, 0); - - if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { - if (control_init(ps, &ps->ps_csock) == -1) - fatalx("%s: control_init", __func__); - TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) - if (control_init(ps, rcs) == -1) - fatalx("%s: control_init", __func__); - } - - /* Use non-standard user */ - if (p->p_pw != NULL) - pw = p->p_pw; - else - pw = ps->ps_pw; - - /* Change root directory */ - if (p->p_chroot != NULL) - root = p->p_chroot; - else - root = pw->pw_dir; - - if (chroot(root) == -1) - fatal("%s: chroot", __func__); - if (chdir("/") == -1) - fatal("%s: chdir(\"/\")", __func__); - - privsep_process = p->p_id; - - setproctitle("%s", p->p_title); - - if (setgroups(1, &pw->pw_gid) || - setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || - setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) - fatal("%s: cannot drop privileges", __func__); - - event_init(); - - signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p); - signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p); - signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); - signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); - signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); - signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p); - - signal_add(&ps->ps_evsigint, NULL); - signal_add(&ps->ps_evsigterm, NULL); - signal_add(&ps->ps_evsigchld, NULL); - signal_add(&ps->ps_evsighup, NULL); - signal_add(&ps->ps_evsigpipe, NULL); - signal_add(&ps->ps_evsigusr1, NULL); - - proc_setup(ps, procs, nproc); - proc_accept(ps, PROC_PARENT_SOCK_FILENO, PROC_PARENT, 0); - if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { - if (control_listen(&ps->ps_csock) == -1) - fatalx("%s: control_listen", __func__); - TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) - if (control_listen(rcs) == -1) - fatalx("%s: control_listen", __func__); - } - - DPRINTF("%s: %s %d/%d, pid %d", __func__, p->p_title, - ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); - - if (run != NULL) - run(ps, p, arg); - - event_dispatch(); - - proc_shutdown(p); -} - -void -proc_dispatch(int fd, short event, void *arg) -{ - struct imsgev *iev = arg; - struct privsep_proc *p = iev->proc; - struct privsep *ps = p->p_ps; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - int verbose; - const char *title; - struct privsep_fd pf; - - title = ps->ps_title[privsep_process]; - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("%s: imsg_read", __func__); - if (n == 0) { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); - return; - } - } - - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("%s: msgbuf_write", __func__); - if (n == 0) { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); - return; - } - } - - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("%s: imsg_get", __func__); - if (n == 0) - break; - -#if DEBUG > 1 - log_debug("%s: %s %d got imsg %d peerid %d from %s %d", - __func__, title, ps->ps_instance + 1, - imsg.hdr.type, imsg.hdr.peerid, p->p_title, imsg.hdr.pid); -#endif - - /* - * Check the message with the program callback - */ - if ((p->p_cb)(fd, p, &imsg) == 0) { - /* Message was handled by the callback, continue */ - imsg_free(&imsg); - continue; - } - - /* - * Generic message handling - */ - switch (imsg.hdr.type) { - case IMSG_CTL_VERBOSE: - IMSG_SIZE_CHECK(&imsg, &verbose); - memcpy(&verbose, imsg.data, sizeof(verbose)); - log_setverbose(verbose); - break; - case IMSG_CTL_PROCFD: - IMSG_SIZE_CHECK(&imsg, &pf); - memcpy(&pf, imsg.data, sizeof(pf)); - proc_accept(ps, imsg.fd, pf.pf_procid, - pf.pf_instance); - break; - default: - fatalx("%s: %s %d got invalid imsg %d peerid %d " - "from %s %d", - __func__, title, ps->ps_instance + 1, - imsg.hdr.type, imsg.hdr.peerid, - p->p_title, imsg.hdr.pid); - } - imsg_free(&imsg); - } - imsg_event_add(iev); -} - -int -proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - return (-1); -} - -/* - * imsg helper functions - */ - -void -imsg_event_add(struct imsgev *iev) -{ - if (iev->handler == NULL) { - imsg_flush(&iev->ibuf); - return; - } - - iev->events = EV_READ; - if (iev->ibuf.w.queued) - iev->events |= EV_WRITE; - - event_del(&iev->ev); - event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); - event_add(&iev->ev, NULL); -} - -int -imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, - pid_t pid, int fd, void *data, uint16_t datalen) -{ - int ret; - - if ((ret = imsg_compose(&iev->ibuf, type, peerid, - pid, fd, data, datalen)) == -1) - return (ret); - imsg_event_add(iev); - return (ret); -} - -int -imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid, - pid_t pid, int fd, const struct iovec *iov, int iovcnt) -{ - int ret; - - if ((ret = imsg_composev(&iev->ibuf, type, peerid, - pid, fd, iov, iovcnt)) == -1) - return (ret); - imsg_event_add(iev); - return (ret); -} - -void -proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) -{ - if (*n == -1) { - /* Use a range of all target instances */ - *n = 0; - *m = ps->ps_instances[id]; - } else { - /* Use only a single slot of the specified peer process */ - *m = *n + 1; - } -} - -int -proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, - uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen) -{ - int m; - - proc_range(ps, id, &n, &m); - for (; n < m; n++) { - if (imsg_compose_event(&ps->ps_ievs[id][n], - type, peerid, ps->ps_instance + 1, fd, data, datalen) == -1) - return (-1); - } - - return (0); -} - -int -proc_compose(struct privsep *ps, enum privsep_procid id, - uint16_t type, void *data, uint16_t datalen) -{ - return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen)); -} - -int -proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, - uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt) -{ - int m; - - proc_range(ps, id, &n, &m); - for (; n < m; n++) - if (imsg_composev_event(&ps->ps_ievs[id][n], - type, peerid, ps->ps_instance + 1, fd, iov, iovcnt) == -1) - return (-1); - - return (0); -} - -int -proc_composev(struct privsep *ps, enum privsep_procid id, - uint16_t type, const struct iovec *iov, int iovcnt) -{ - return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt)); -} - -int -proc_forward_imsg(struct privsep *ps, struct imsg *imsg, - enum privsep_procid id, int n) -{ - return (proc_compose_imsg(ps, id, n, imsg->hdr.type, - imsg->hdr.peerid, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); -} - -struct imsgbuf * -proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) -{ - int m; - - proc_range(ps, id, &n, &m); - return (&ps->ps_ievs[id][n].ibuf); -} - -struct imsgev * -proc_iev(struct privsep *ps, enum privsep_procid id, int n) -{ - int m; - - proc_range(ps, id, &n, &m); - return (&ps->ps_ievs[id][n]); -} - -/* This function should only be called with care as it breaks async I/O */ -int -proc_flush_imsg(struct privsep *ps, enum privsep_procid id, int n) -{ - struct imsgbuf *ibuf; - int m, ret = 0; - - proc_range(ps, id, &n, &m); - for (; n < m; n++) { - if ((ibuf = proc_ibuf(ps, id, n)) == NULL) - return (-1); - do { - ret = imsg_flush(ibuf); - } while (ret == -1 && errno == EAGAIN); - if (ret == -1) - break; - imsg_event_add(&ps->ps_ievs[id][n]); - } - - return (ret); -} diff --git a/usr.sbin/switchd/proc.h b/usr.sbin/switchd/proc.h deleted file mode 100644 index b79c51e9bfb..00000000000 --- a/usr.sbin/switchd/proc.h +++ /dev/null @@ -1,190 +0,0 @@ -/* $OpenBSD: proc.h,v 1.9 2021/04/20 21:11:56 dv Exp $ */ - -/* - * Copyright (c) 2010-2015 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include "types.h" - -#ifndef _PROC_H -#define _PROC_H - -struct control_sock { - const char *cs_name; - struct event cs_ev; - struct event cs_evt; - int cs_fd; - int cs_restricted; - void *cs_env; - - TAILQ_ENTRY(control_sock) cs_entry; -}; -TAILQ_HEAD(control_socks, control_sock); - -struct privsep_pipes { - int *pp_pipes[PROC_MAX]; -}; - -struct privsep { - struct privsep_pipes *ps_pipes[PROC_MAX]; - struct privsep_pipes *ps_pp; - - struct imsgev *ps_ievs[PROC_MAX]; - const char *ps_title[PROC_MAX]; - pid_t ps_pid[PROC_MAX]; - struct passwd *ps_pw; - int ps_noaction; - - struct control_sock ps_csock; - struct control_socks ps_rcsocks; - - unsigned int ps_instances[PROC_MAX]; - unsigned int ps_instance; - - /* Event and signal handlers */ - struct event ps_evsigint; - struct event ps_evsigterm; - struct event ps_evsigchld; - struct event ps_evsighup; - struct event ps_evsigpipe; - struct event ps_evsigusr1; - - void *ps_env; -}; - -struct privsep_proc { - const char *p_title; - enum privsep_procid p_id; - int (*p_cb)(int, struct privsep_proc *, - struct imsg *); - void (*p_init)(struct privsep *, - struct privsep_proc *); - const char *p_chroot; - struct privsep *p_ps; - void (*p_shutdown)(void); - struct passwd *p_pw; -}; - -struct privsep_fd { - enum privsep_procid pf_procid; - unsigned int pf_instance; -}; - -struct imsgev { - struct imsgbuf ibuf; - void (*handler)(int, short, void *); - struct event ev; - struct privsep_proc *proc; - void *data; - short events; - const char *name; -}; - -#ifndef IMSG_DATA_SIZE -#define IMSG_DATA_SIZE(_imsg) ((_imsg)->hdr.len - IMSG_HEADER_SIZE) -#endif - -#ifndef IMSG_SIZE_CHECK -#define IMSG_SIZE_CHECK(_imsg, _type) \ - do { \ - if (IMSG_DATA_SIZE(_imsg) < sizeof(*(_type))) \ - fatal("received imsg size was wrong."); \ - } while (0 /* CONSTCOND */) -#endif - -#if DEBUG -#define DPRINTF log_debug -#else -#define DPRINTF(x...) do {} while(0) -#endif - -#define PROC_PARENT_SOCK_FILENO 3 -#define PROC_MAX_INSTANCES 32 - -struct ctl_conn { - TAILQ_ENTRY(ctl_conn) entry; - uint8_t flags; -#define CTL_CONN_NOTIFY 0x01 - struct imsgev iev; - int restricted; -}; -TAILQ_HEAD(ctl_connlist, ctl_conn); - -/* proc.c */ -void proc_init(struct privsep *, struct privsep_proc *, unsigned int, int, - int, char **, enum privsep_procid); -void proc_kill(struct privsep *); -void proc_connect(struct privsep *ps); -void proc_dispatch(int, short event, void *); -void proc_run(struct privsep *, struct privsep_proc *, - struct privsep_proc *, unsigned int, - void (*)(struct privsep *, struct privsep_proc *, void *), void *); -void imsg_event_add(struct imsgev *); -int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, - pid_t, int, void *, uint16_t); -int imsg_composev_event(struct imsgev *, uint16_t, uint32_t, - pid_t, int, const struct iovec *, int); -int proc_compose_imsg(struct privsep *, enum privsep_procid, int, - uint16_t, uint32_t, int, void *, uint16_t); -int proc_compose(struct privsep *, enum privsep_procid, - uint16_t, void *data, uint16_t); -int proc_composev_imsg(struct privsep *, enum privsep_procid, int, - uint16_t, uint32_t, int, const struct iovec *, int); -int proc_composev(struct privsep *, enum privsep_procid, - uint16_t, const struct iovec *, int); -int proc_forward_imsg(struct privsep *, struct imsg *, - enum privsep_procid, int); -struct imsgbuf * - proc_ibuf(struct privsep *, enum privsep_procid, int); -struct imsgev * - proc_iev(struct privsep *, enum privsep_procid, int); -enum privsep_procid - proc_getid(struct privsep_proc *, unsigned int, const char *); -int proc_flush_imsg(struct privsep *, enum privsep_procid, int); - -/* control.c */ -int control_init(struct privsep *, struct control_sock *); -int control_listen(struct control_sock *); -struct ctl_conn - *control_connbyfd(int); -void control(struct privsep *, struct privsep_proc *); - -/* log.c */ -void log_init(int, int); -void log_procinit(const char *); -void log_setverbose(int); -int log_getverbose(void); -void log_warn(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_warnx(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_info(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_debug(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void logit(int, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); -void vlog(int, const char *, va_list) - __attribute__((__format__ (printf, 2, 0))); -__dead void fatal(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -__dead void fatalx(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); - -void socket_set_blockmode(int, enum blockmodes); - -#endif /* _PROC_H */ diff --git a/usr.sbin/switchd/switch.c b/usr.sbin/switchd/switch.c deleted file mode 100644 index 285add7bacc..00000000000 --- a/usr.sbin/switchd/switch.c +++ /dev/null @@ -1,248 +0,0 @@ -/* $OpenBSD: switch.c,v 1.3 2016/09/18 13:17:40 rzalamena Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "switchd.h" - -void switch_timer(struct switchd *, void *); - -static __inline int - switch_cmp(struct switch_control *, struct switch_control *); -static __inline int - switch_maccmp(struct macaddr *, struct macaddr *); - -void -switch_init(struct switchd *sc) -{ - RB_INIT(&sc->sc_switches); -} - -int -switch_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - struct privsep *ps = p->p_ps; - struct switchd *sc = ps->ps_env; - struct switch_control *sw; - struct macaddr *mac; - struct iovec iov[2]; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_SUM: - IMSG_SIZE_CHECK(imsg, &fd); - - RB_FOREACH(sw, switch_head, &sc->sc_switches) { - iov[0].iov_base = imsg->data; - iov[0].iov_len = IMSG_DATA_SIZE(imsg); - iov[1].iov_base = sw; - iov[1].iov_len = sizeof(*sw); - - proc_composev(ps, PROC_CONTROL, - IMSG_CTL_SWITCH, iov, 2); - - RB_FOREACH(mac, macaddr_head, &sw->sw_addrcache) { - iov[0].iov_base = imsg->data; - iov[0].iov_len = IMSG_DATA_SIZE(imsg); - iov[1].iov_base = mac; - iov[1].iov_len = sizeof(*mac); - - proc_composev(ps, PROC_CONTROL, - IMSG_CTL_MAC, iov, 2); - } - } - - proc_compose(ps, PROC_CONTROL, - IMSG_CTL_END, imsg->data, IMSG_DATA_SIZE(imsg)); - return (0); - default: - break; - } - - return (-1); -} - -struct switch_control * -switch_get(struct switch_connection *con) -{ - struct switchd *sc = con->con_sc; - struct switch_control key; - - memcpy(&key.sw_addr, &con->con_peer, sizeof(key.sw_addr)); - - con->con_switch = RB_FIND(switch_head, &sc->sc_switches, &key); - return (con->con_switch); -} - -struct switch_control * -switch_add(struct switch_connection *con) -{ - struct switchd *sc = con->con_sc; - struct switch_control *sw, *oldsw; - static unsigned int id = 0; - - /* Connection already has an associated switch */ - if (con->con_switch != NULL) - return (NULL); - - if ((sw = calloc(1, sizeof(*sw))) == NULL) - return (NULL); - - memcpy(&sw->sw_addr, &con->con_peer, sizeof(sw->sw_addr)); - sw->sw_id = ++id; - RB_INIT(&sw->sw_addrcache); - - if ((oldsw = - RB_INSERT(switch_head, &sc->sc_switches, sw)) != NULL) { - free(sw); - sw = oldsw; - } else { - timer_set(sc, &sw->sw_timer, switch_timer, sw); - timer_add(sc, &sw->sw_timer, sc->sc_cache_timeout); - } - - con->con_switch = sw; - return (con->con_switch); -} - -void -switch_timer(struct switchd *sc, void *arg) -{ - struct switch_control *sw = arg; - struct macaddr *mac, *next; - struct timeval tv; - unsigned int cnt = 0; - - getmonotime(&tv); - - for (mac = RB_MIN(macaddr_head, &sw->sw_addrcache); - mac != NULL; mac = next) { - next = RB_NEXT(macaddr_head, &sw->sw_addrcache, mac); - - /* Simple monotonic timeout */ - if ((tv.tv_sec - mac->mac_age) >= sc->sc_cache_timeout) { - RB_REMOVE(macaddr_head, &sw->sw_addrcache, mac); - sw->sw_cachesize--; - free(mac); - cnt++; - } - } - if (cnt) - log_debug("%s: flushed %d mac from switch %u after timeout", - __func__, cnt, sw->sw_id); - - timer_add(sc, &sw->sw_timer, sc->sc_cache_timeout); -} - -void -switch_remove(struct switchd *sc, struct switch_control *sw) -{ - struct macaddr *mac, *next; - - if (sw == NULL) - return; - - timer_del(sc, &sw->sw_timer); - - for (mac = RB_MIN(macaddr_head, &sw->sw_addrcache); - mac != NULL; mac = next) { - next = RB_NEXT(macaddr_head, &sw->sw_addrcache, mac); - RB_REMOVE(macaddr_head, &sw->sw_addrcache, mac); - sw->sw_cachesize--; - free(mac); - } - RB_REMOVE(switch_head, &sc->sc_switches, sw); - - log_debug("%s: switch %u removed", __func__, sw->sw_id); - - free(sw); -} - -struct macaddr * -switch_learn(struct switchd *sc, struct switch_control *sw, - uint8_t *ea, uint32_t port) -{ - struct macaddr *mac, *oldmac = NULL; - struct timeval tv; - - if ((mac = oldmac = switch_cached(sw, ea)) != NULL) - goto update; - - if (sw->sw_cachesize >= sc->sc_cache_max) - return (NULL); - - if ((mac = calloc(1, sizeof(*mac))) == NULL) - return (NULL); - - memcpy(&mac->mac_addr, ea, sizeof(mac->mac_addr)); - - if (RB_INSERT(macaddr_head, &sw->sw_addrcache, mac) != NULL) - fatalx("cache corrupted"); - sw->sw_cachesize++; - - update: - getmonotime(&tv); - mac->mac_port = port; - mac->mac_age = tv.tv_sec; - - log_debug("%s: %s mac %s on switch %u port %u", - __func__, oldmac == NULL ? "learned new" : "updated", - print_ether(ea), sw->sw_id, port); - - return (mac); -} - -struct macaddr * -switch_cached(struct switch_control *sw, uint8_t *ea) -{ - struct macaddr key; - memcpy(&key.mac_addr, ea, sizeof(key.mac_addr)); - return (RB_FIND(macaddr_head, &sw->sw_addrcache, &key)); -} - -static __inline int -switch_cmp(struct switch_control *a, struct switch_control *b) -{ - int diff = 0; - - diff = sockaddr_cmp((struct sockaddr *)&a->sw_addr, - (struct sockaddr *)&b->sw_addr, 128); - if (!diff) - diff = socket_getport(&a->sw_addr) - - socket_getport(&b->sw_addr); - - return (diff); -} - -static __inline int -switch_maccmp(struct macaddr *a, struct macaddr *b) -{ - return (memcmp(a->mac_addr, b->mac_addr, sizeof(a->mac_addr))); -} - -RB_GENERATE(switch_head, switch_control, sw_entry, switch_cmp); -RB_GENERATE(macaddr_head, macaddr, mac_entry, switch_maccmp); diff --git a/usr.sbin/switchd/switchd.8 b/usr.sbin/switchd/switchd.8 deleted file mode 100644 index c94ce86567b..00000000000 --- a/usr.sbin/switchd/switchd.8 +++ /dev/null @@ -1,97 +0,0 @@ -.\" $OpenBSD: switchd.8,v 1.4 2016/11/29 07:18:23 jmc Exp $ -.\" -.\" Copyright (c) 2016 Reyk Floeter -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: November 29 2016 $ -.Dt SWITCHD 8 -.Os -.Sh NAME -.Nm switchd -.Nd software-defined networking (SDN) sflow controller -.Sh SYNOPSIS -.Nm switchd -.Op Fl dnv -.Op Fl c Ar cachesize -.Op Fl D Ar macro Ns = Ns Ar value -.Op Fl f Ar file -.Op Fl t Ar timeout -.Sh DESCRIPTION -.Nm -is a controller for software-defined networking (SDN) and is -compatible with the OpenFlow protocol. -.Pp -The options are as follows: -.Bl -tag -width "-c cachesize" -.It Fl c Ar cachesize -Number of MAC addresses to cache. -The default is 4096. -.It Fl D Ar macro Ns = Ns Ar value -Set a -.Ar macro -to a -.Ar value . -Macros can be referenced in the configuration files. -.It Fl d -Debug mode. -Don't detach or become a daemon. -This allows for easy monitoring of -.Nm . -.It Fl f Ar file -Specifies the configuration file. -The default is -.Pa /etc/switchd.conf . -.It Fl n -Check that the configuration is valid, but don't start the daemon. -.It Fl t Ar timeout -Timeout in seconds for learned MAC addresses. -The default is 240 seconds. -.It Fl v -Verbose mode. -Multiple -.Fl v -options increase the verbosity. -.El -.Sh FILES -.Bl -tag -width "/etc/switchd.conf" -compact -.It Pa /etc/switchd.conf -Default configuration file. -.El -.Sh SEE ALSO -.Xr switchd.conf 5 , -.Xr switchctl 8 -.Sh STANDARDS -.Rs -.%A Open Networking Foundation (ONF) -.%D December 31, 2009 -.%R Version 1.0.0 (Wire Protocol 0x01) -.%T OpenFlow Switch Specification -.Re -.Pp -.Rs -.%A Open Networking Foundation (ONF) -.%D March 26, 2015 -.%R Version 1.3.5 (Protocol version 0x04) -.%T OpenFlow Switch Specification -.Re -.Sh HISTORY -The -.Nm -program first appeared in -.Ox 6.1 . -.Sh AUTHORS -The -.Nm -program was written by -.An Reyk Floeter Aq Mt reyk@openbsd.org . diff --git a/usr.sbin/switchd/switchd.c b/usr.sbin/switchd/switchd.c deleted file mode 100644 index f1410c32fd0..00000000000 --- a/usr.sbin/switchd/switchd.c +++ /dev/null @@ -1,617 +0,0 @@ -/* $OpenBSD: switchd.c,v 1.20 2021/09/06 13:32:18 deraadt Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" - -void parent_shutdown(struct switchd *); -void parent_sig_handler(int, short, void *); -int parent_dispatch_ofp(int, struct privsep_proc *, struct imsg *); -int parent_dispatch_control(int, struct privsep_proc *, struct imsg *); -int parent_configure(struct switchd *); -int parent_reload(struct switchd *); -void parent_connect(struct privsep *, struct switch_client *); -void parent_connected(int, short, void *); -void parent_disconnect(struct privsep *, struct switch_client *); - -__dead void usage(void); - -static struct privsep_proc procs[] = { - { "ofp", PROC_OFP, NULL, ofp }, - { "control", PROC_CONTROL, parent_dispatch_control, control }, - { "ofcconn", PROC_OFCCONN, NULL, ofcconn } -}; - -enum privsep_procid privsep_process; - -__dead void -usage(void) -{ - extern const char *__progname; - fprintf(stderr, "usage: %s [-dnv] [-c cachesize] [-D macro=value] " - "[-f file] [-t timeout]\n", - __progname); - exit(1); -} - -int -main(int argc, char *argv[]) -{ - struct switchd *sc = NULL; - struct privsep *ps = NULL; - struct switch_server *srv; - const char *errstr = NULL; - int c; - int debug = 0, verbose = 0; - uint32_t opts = 0; - unsigned int cache = SWITCHD_CACHE_MAX; - unsigned int timeout = SWITCHD_CACHE_TIMEOUT; - const char *conffile = SWITCHD_CONFIG; - const char *errp, *title = NULL; - enum privsep_procid proc_id = PROC_PARENT; - int argc0 = argc, proc_instance = 0; - - log_init(1, LOG_DAEMON); - - while ((c = getopt(argc, argv, "c:dD:f:hI:nP:t:v")) != -1) { - switch (c) { - case 'c': - cache = strtonum(optarg, 1, UINT32_MAX, &errstr); - if (errstr != NULL) { - log_warn("max cache size: %s", errstr); - usage(); - } - break; - case 'd': - debug++; - break; - case 'D': - if (cmdline_symset(optarg) < 0) - log_warnx("could not parse macro definition %s", - optarg); - break; - case 'f': - conffile = optarg; - break; - case 'I': - proc_instance = strtonum(optarg, 0, - PROC_MAX_INSTANCES, &errp); - if (errp) - fatalx("invalid process instance"); - break; - case 'n': - opts |= SWITCHD_OPT_NOACTION; - break; - case 'P': - title = optarg; - proc_id = proc_getid(procs, nitems(procs), title); - if (proc_id == PROC_MAX) - fatalx("invalid process name"); - break; - case 't': - timeout = strtonum(optarg, 0, UINT32_MAX, &errstr); - if (errstr != NULL) { - log_warn("cache timeout: %s", errstr); - usage(); - } - break; - case 'v': - verbose++; - opts |= SWITCHD_OPT_VERBOSE; - break; - default: - usage(); - } - } - - if ((sc = calloc(1, sizeof(*sc))) == NULL) - fatal("calloc"); - - if (strlcpy(sc->sc_conffile, conffile, PATH_MAX) >= PATH_MAX) - fatal("config file exceeds PATH_MAX"); - - sc->sc_cache_max = cache; - sc->sc_cache_timeout = timeout; - sc->sc_opts = opts; - - srv = &sc->sc_server; - srv->srv_sc = sc; - - ps = &sc->sc_ps; - ps->ps_env = sc; - TAILQ_INIT(&ps->ps_rcsocks); - TAILQ_INIT(&sc->sc_clients); - - if (parse_config(sc->sc_conffile, sc) == -1) { - proc_kill(&sc->sc_ps); - exit(1); - } - - if (opts & SWITCHD_OPT_NOACTION) { - fprintf(stderr, "configuration OK\n"); - proc_kill(&sc->sc_ps); - exit(0); - } - - /* check for root privileges */ - if (geteuid()) - fatalx("need root privileges"); - - if ((ps->ps_pw = getpwnam(SWITCHD_USER)) == NULL) - fatalx("unknown user " SWITCHD_USER); - - log_init(debug, LOG_DAEMON); - log_setverbose(verbose); - - /* Configure the control socket */ - ps->ps_csock.cs_name = SWITCHD_SOCKET; - ps->ps_instance = proc_instance; - if (title) - ps->ps_title[proc_id] = title; - - /* Only the parent returns. */ - proc_init(ps, procs, nitems(procs), debug, argc0, argv, proc_id); - - if (!debug && daemon(0, 0) == -1) - fatal("failed to daemonize"); - - log_procinit("parent"); - - if (unveil("/", "r") == -1) - fatal("unveil /"); - if (unveil("/dev", "rw") == -1) - fatal("unveil"); - /* - * pledge in the parent process: - * stdio - for malloc and basic I/O including events. - * rpath - for reload to open and read the configuration files. - * wpath - for accessing the /dev/switch device. - * inet - for opening OpenFlow and device sockets. - * dns - for resolving host in the configuration files. - * sendfd - send sockets to child processes on reload. - */ - if (pledge("stdio rpath wpath inet dns sendfd", NULL) == -1) - fatal("pledge"); - - event_init(); - - signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps); - signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps); - signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps); - signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps); - signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps); - - signal_add(&ps->ps_evsigint, NULL); - signal_add(&ps->ps_evsigterm, NULL); - signal_add(&ps->ps_evsighup, NULL); - signal_add(&ps->ps_evsigpipe, NULL); - signal_add(&ps->ps_evsigusr1, NULL); - - proc_connect(ps); - - if (parent_configure(sc) == -1) - fatalx("configuration failed"); - - event_dispatch(); - - log_debug("%d parent exiting", getpid()); - - return (0); -} - -int -switchd_socket(struct sockaddr *sock, int reuseport) -{ - int s = -1, val; - struct linger lng; - - if ((s = socket(sock->sa_family, SOCK_STREAM | SOCK_NONBLOCK, - IPPROTO_TCP)) == -1) - goto bad; - - /* - * Socket options - */ - bzero(&lng, sizeof(lng)); - if (setsockopt(s, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1) - goto bad; - if (reuseport) { - val = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val, - sizeof(int)) == -1) - goto bad; - } - - /* - * TCP options - */ - val = 1; - if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, - &val, sizeof(val)) == -1) - goto bad; - - return (s); - - bad: - if (s != -1) - close(s); - return (-1); -} - -int -switchd_listen(struct sockaddr *sock) -{ - int s; - - if ((s = switchd_socket(sock, 1)) == -1) - return (-1); - - if (bind(s, sock, sock->sa_len) == -1) - goto bad; - if (listen(s, 10) == -1) - goto bad; - - return (s); - - bad: - close(s); - return (-1); -} - -int -switchd_tap(void) -{ - char path[PATH_MAX]; - int i, fd; - - for (i = 0; i < SWITCHD_MAX_TAP; i++) { - snprintf(path, PATH_MAX, "/dev/tap%d", i); - fd = open(path, O_RDWR | O_NONBLOCK); - if (fd != -1) - return (fd); - } - - return (-1); -} - -struct switch_connection * -switchd_connbyid(struct switchd *sc, unsigned int id, unsigned int instance) -{ - struct switch_connection *con; - - TAILQ_FOREACH(con, &sc->sc_conns, con_entry) { - if (con->con_id == id && con->con_instance == instance) - return (con); - } - - return (NULL); -} - -struct switch_connection * -switchd_connbyaddr(struct switchd *sc, struct sockaddr *sa) -{ - struct switch_connection *con; - - TAILQ_FOREACH(con, &sc->sc_conns, con_entry) { - if (sockaddr_cmp((struct sockaddr *) - &con->con_peer, sa, -1) == 0) - return (con); - } - - return (NULL); -} - -void -parent_sig_handler(int sig, short event, void *arg) -{ - struct privsep *ps = arg; - - switch (sig) { - case SIGHUP: - log_info("%s: reload requested with SIGHUP", __func__); - - /* - * This is safe because libevent uses async signal handlers - * that run in the event loop and not in signal context. - */ - parent_reload(ps->ps_env); - break; - case SIGPIPE: - log_info("%s: ignoring SIGPIPE", __func__); - break; - case SIGUSR1: - log_info("%s: ignoring SIGUSR1", __func__); - break; - case SIGTERM: - case SIGINT: - parent_shutdown(ps->ps_env); - break; - default: - fatalx("unexpected signal"); - } -} - -int -parent_configure(struct switchd *sc) -{ - struct switch_client *swc, *swcn; - int fd; - - if ((fd = switchd_tap()) == -1) - fatal("%s: tap", __func__); - proc_compose_imsg(&sc->sc_ps, PROC_OFP, -1, - IMSG_TAPFD, -1, fd, NULL, 0); - - TAILQ_FOREACH_SAFE(swc, &sc->sc_clients, swc_next, swcn) { - parent_connect(&sc->sc_ps, swc); - } - - return (0); -} - -int -parent_reload(struct switchd *sc) -{ - struct switchd newconf; - struct switch_client *swc, *oswc, *swcn; - - memset(&newconf, 0, sizeof(newconf)); - TAILQ_INIT(&newconf.sc_clients); - TAILQ_INIT(&newconf.sc_conns); - - if (parse_config(sc->sc_conffile, &newconf) != -1) { - TAILQ_FOREACH_SAFE(swc, &sc->sc_clients, swc_next, swcn) { - TAILQ_FOREACH(oswc, &newconf.sc_clients, swc_next) { - if (sockaddr_cmp((struct sockaddr *) - &oswc->swc_addr.swa_addr, - (struct sockaddr *) - &swc->swc_addr.swa_addr, -1) == 0) { - TAILQ_REMOVE(&newconf.sc_clients, - oswc, swc_next); - break; - } - } - if (oswc == NULL) { - /* Removed */ - parent_disconnect(&sc->sc_ps, swc); - } else { - /* Keep the existing one */ - TAILQ_REMOVE(&newconf.sc_clients, - oswc, swc_next); - free(oswc); - } - } - TAILQ_FOREACH_SAFE(swc, &newconf.sc_clients, swc_next, swcn) { - TAILQ_REMOVE(&newconf.sc_clients, swc, swc_next); - TAILQ_INSERT_TAIL(&sc->sc_clients, swc, swc_next); - - parent_connect(&sc->sc_ps, swc); - } - } - - return (0); -} - -int -parent_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - struct switch_client *swc, *oswc; - struct privsep *ps = p->p_ps; - struct switchd *sc = ps->ps_env; - - switch (imsg->hdr.type) { - case IMSG_CTL_CONNECT: - case IMSG_CTL_DISCONNECT: - IMSG_SIZE_CHECK(imsg, swc); - - /* Need to allocate it in case it is reused */ - if ((swc = calloc(1, sizeof(*swc))) == NULL) { - log_warnx("%s: calloc", __func__); - return (0); - } - memcpy(swc, imsg->data, sizeof(*swc)); - memset(&swc->swc_ev, 0, sizeof(swc->swc_ev)); - - if (imsg->hdr.type == IMSG_CTL_CONNECT) { - TAILQ_INSERT_TAIL(&sc->sc_clients, swc, swc_next); - parent_connect(p->p_ps, swc); - } else { - TAILQ_FOREACH(oswc, &sc->sc_clients, swc_next) { - if (sockaddr_cmp((struct sockaddr *) - &oswc->swc_addr.swa_addr, - (struct sockaddr *) - &swc->swc_addr.swa_addr, -1) == 0) { - parent_disconnect(ps, oswc); - break; - } - } - if (oswc == NULL) - log_warnx("client %s is not connected", - print_host(&swc->swc_addr.swa_addr, - NULL, 0)); - free(swc); - } - return (0); - default: - break; - } - - return (-1); -} - -void -parent_shutdown(struct switchd *sc) -{ - proc_kill(&sc->sc_ps); - - free(sc); - - log_warnx("parent terminating"); - exit(0); -} - -void -parent_connect(struct privsep *ps, struct switch_client *swc) -{ - struct switchd *sc = ps->ps_env; - struct sockaddr_storage *ss; - struct sockaddr_un *un; - struct sockaddr_in *sin4; - struct sockaddr_in6 *sin6; - int fd = -1; - struct timeval tv; - - ss = &swc->swc_addr.swa_addr; - - if (ss->ss_len == 0) { - log_warnx("%s: invalid address", __func__); - goto fail; - } - swc->swc_arg = ps; - memset(&swc->swc_ev, 0, sizeof(swc->swc_ev)); - - switch (ss->ss_family) { - case AF_LOCAL: - un = (struct sockaddr_un *)ss; - - /* restrict the opening path to /dev/switch* */ - if (strncmp(un->sun_path, "/dev/switch", - strlen("/dev/switch")) != 0) { - log_warnx("%s: device path is wrong: %s", __func__, - un->sun_path); - goto fail; - } - - if ((fd = open(un->sun_path, O_RDWR | O_NONBLOCK)) == -1) { - log_warn("%s: failed to open %s", - __func__, un->sun_path); - goto fail; - } - break; - case AF_INET: - case AF_INET6: - if (ss->ss_family == AF_INET) { - sin4 = (struct sockaddr_in *)ss; - if (sin4->sin_port == 0) - sin4->sin_port = htons(SWITCHD_CTLR_PORT); - } else if (ss->ss_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *)ss; - if (sin6->sin6_port == 0) - sin6->sin6_port = htons(SWITCHD_CTLR_PORT); - } - - if ((fd = switchd_socket((struct sockaddr *)ss, 0)) == -1) { - log_debug("%s: failed to get socket for %s", __func__, - print_host(ss, NULL, 0)); - goto fail; - } - - retry: - if (connect(fd, (struct sockaddr *)ss, ss->ss_len) == -1) { - if (errno == EINTR) - goto retry; - if (errno == EINPROGRESS) { - tv.tv_sec = SWITCHD_CONNECT_TIMEOUT; - tv.tv_usec = 0; - event_set(&swc->swc_ev, fd, EV_WRITE|EV_TIMEOUT, - parent_connected, swc); - event_add(&swc->swc_ev, &tv); - return; - } - - log_warn("%s: failed to connect to %s, fd %d", __func__, - print_host(ss, NULL, 0), fd); - goto fail; - } - - break; - } - - parent_connected(fd, 0, swc); - return; - - fail: - TAILQ_REMOVE(&sc->sc_clients, swc, swc_next); - free(swc); -} - -void -parent_connected(int fd, short event, void *arg) -{ - struct switch_client *swc = arg; - struct privsep *ps = swc->swc_arg; - struct switchd *sc = ps->ps_env; - - if (event & EV_TIMEOUT) { - log_debug("%s: failed to connect to %s", __func__, - print_host(&swc->swc_addr.swa_addr, NULL, 0)); - TAILQ_REMOVE(&sc->sc_clients, swc, swc_next); - free(swc); - return; - } - - switch (swc->swc_target.swa_type) { - case SWITCH_CONN_LOCAL: - proc_compose_imsg(ps, PROC_OFP, -1, IMSG_CTL_CONNECT, - -1, fd, swc, sizeof(*swc)); - break; - case SWITCH_CONN_TLS: - case SWITCH_CONN_TCP: - proc_compose_imsg(ps, PROC_OFCCONN, -1, IMSG_CTL_CONNECT, - -1, fd, swc, sizeof(*swc)); - break; - default: - fatalx("not implemented"); - } -} - -void -parent_disconnect(struct privsep *ps, struct switch_client *swc) -{ - struct switchd *sc = ps->ps_env; - enum privsep_procid target; - - TAILQ_REMOVE(&sc->sc_clients, swc, swc_next); - - target = swc->swc_target.swa_type == SWITCH_CONN_LOCAL ? - PROC_OFP : PROC_OFCCONN; - proc_compose(ps, target, IMSG_CTL_DISCONNECT, swc, sizeof(*swc)); - - free(swc); -} diff --git a/usr.sbin/switchd/switchd.conf.5 b/usr.sbin/switchd/switchd.conf.5 deleted file mode 100644 index dcf74676541..00000000000 --- a/usr.sbin/switchd/switchd.conf.5 +++ /dev/null @@ -1,119 +0,0 @@ -.\" $OpenBSD: switchd.conf.5,v 1.10 2019/07/11 09:28:54 sthen Exp $ -.\" -.\" Copyright (c) 2014, 2015, 2016 Reyk Floeter -.\" Copyright (c) 2016 YASUOKA Masahiko -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.\" The following requests are required for all man pages. -.\" -.Dd $Mdocdate: July 11 2019 $ -.Dt SWITCHD.CONF 5 -.Os -.Sh NAME -.Nm switchd.conf -.Nd switch daemon configuration file -.Sh DESCRIPTION -.Nm -is the configuration file for the switch daemon, -.Xr switchd 8 . -.Pp -.Nm -files is divided into the following main sections: -.Bl -tag -width xxxx -.It Sy Macros -User-defined variables may be defined and used later, simplifying the -configuration file. -.It Sy Global Configuration -Global runtime settings for -.Xr switchd 8 . -.El -.Pp -The current line can be extended over multiple lines using a backslash -.Pq Sq \e . -Comments can be put anywhere in the file using a hash mark -.Pq Sq # , -and extend to the end of the current line. -Care should be taken when commenting out multi-line text: -the comment is effective until the end of the entire block. -.Pp -Argument names not beginning with a letter, digit, or underscore -must be quoted. -.Pp -Additional configuration files can be included with the -.Ic include -keyword, for example: -.Bd -literal -offset indent -include "/etc/switchd.conf.local" -.Ed -.Sh MACROS -Macros can be defined that will later be expanded in context. -Macro names must start with a letter, digit, or underscore, -and may contain any of those characters. -Macro names may not be reserved words (for example, -.Ic directory , -.Ic log , -or -.Ic root ) . -Macros are not expanded inside quotes. -.Pp -For example: -.Bd -literal -offset indent -ext_ip="10.0.0.1" -listen on $ext_ip -.Ed -.Sh GLOBAL CONFIGURATION -The following options can be set globally: -.Bl -tag -width Ds -.It Ic listen on Ar address Oo Ic tls Oc Op Ic port Ar port -Set the listen address and port to accept connections from remote -OpenFlow switches. -Secure connections can be enabled with the optional -.Ic tls -keyword. -By default, -.Xr switchd 8 -uses port 6653 and listen address 0.0.0.0. -.\".It Ic device on Ar device-name Oo Ic forward to Ar uri Oc -.\"Attach to a -.\".Xr switch 4 -.\"device. -.\"When attached, -.\".Xr switchd 8 -.\"will accept OpenFlow messages from the connected kernel interface. -.\"The daemon either handles the requests locally or sends them to a remote -.\"controller if the -.\".Ic forward to -.\"directive is set. -.\"The -.\".Ar uri -.\"is the method and address to connect to the remote controller, -.\"with the format -.\".Ar protocol:address:port -.\"where the -.\".Ar protocol -.\"can be either -.\".Dq tcp -.\"or -.\".Dq tls . -.El -.Sh EXAMPLES -The following example is a typical one. -.Bd -literal -offset indent -listen on 0.0.0.0 port 6653 -.\"device "/dev/switch0" -.\"device "/dev/switch1" forward to tcp:192.168.0.1:6653 -.Ed -.Sh SEE ALSO -.Xr switchctl 8 , -.Xr switchd 8 diff --git a/usr.sbin/switchd/switchd.h b/usr.sbin/switchd/switchd.h deleted file mode 100644 index 9dfa9d088a5..00000000000 --- a/usr.sbin/switchd/switchd.h +++ /dev/null @@ -1,430 +0,0 @@ -/* $OpenBSD: switchd.h,v 1.30 2019/11/21 06:22:57 akoshibe Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef SWITCHD_H -#define SWITCHD_H - -#include -#include -#include - -#include - -#include -#include - -#include "ofp10.h" -#include "types.h" -#include "proc.h" -#include "ofp_map.h" - -struct switchd; - -struct timer { - struct event tmr_ev; - struct switchd *tmr_sc; - void (*tmr_cb)(struct switchd *, void *); - void *tmr_cbarg; -}; - -struct packet { - union { - struct ether_header *pkt_eh; - uint8_t *pkt_buf; - }; - size_t pkt_len; -}; - -struct macaddr { - uint8_t mac_addr[ETHER_ADDR_LEN]; - uint32_t mac_port; - time_t mac_age; - RB_ENTRY(macaddr) mac_entry; -}; -RB_HEAD(macaddr_head, macaddr); - -struct switch_control { - unsigned int sw_id; - struct sockaddr_storage sw_addr; - struct macaddr_head sw_addrcache; - struct timer sw_timer; - unsigned int sw_cachesize; - RB_ENTRY(switch_control) sw_entry; -}; -RB_HEAD(switch_head, switch_control); - -struct switch_table { - TAILQ_ENTRY(switch_table) st_entry; - - int st_table; - unsigned int st_entries; - unsigned int st_maxentries; - - uint32_t st_actions; - uint32_t st_actionsmiss; - - uint32_t st_instructions; - uint32_t st_instructionsmiss; - - uint64_t st_setfield; - uint64_t st_setfieldmiss; - uint64_t st_match; - uint64_t st_wildcard; - - /* Maximum of 256 tables (64 * 4). */ - uint64_t st_nexttable[4]; - uint64_t st_nexttablemiss[4]; -}; -TAILQ_HEAD(switch_table_list, switch_table); - -struct multipart_message { - SLIST_ENTRY(multipart_message) - mm_entry; - - uint32_t mm_xid; - uint8_t mm_type; -}; -SLIST_HEAD(multipart_list, multipart_message); - -struct switch_address { - enum switch_conn_type swa_type; - struct sockaddr_storage swa_addr; -}; - -struct switch_connection { - unsigned int con_id; - unsigned int con_instance; - - int con_fd; - int con_inflight; - - struct sockaddr_storage con_peer; - struct sockaddr_storage con_local; - in_port_t con_port; - uint32_t con_xidnxt; - int con_version; - enum ofp_state con_state; - - struct event con_ev; - struct ibuf *con_rbuf; - struct msgbuf con_wbuf; - - struct switch_control *con_switch; - struct switchd *con_sc; - struct switch_server *con_srv; - - struct multipart_list con_mmlist; - struct switch_table_list - con_stlist; - - TAILQ_ENTRY(switch_connection) - con_entry; -}; -TAILQ_HEAD(switch_connections, switch_connection); - -struct switch_server { - int srv_fd; - int srv_tls; - struct sockaddr_storage srv_addr; - struct event srv_ev; - struct event srv_evt; - struct switchd *srv_sc; -}; - -struct switch_client { - struct switch_address swc_addr; - struct switch_address swc_target; - struct event swc_ev; - void *swc_arg; - TAILQ_ENTRY(switch_client) - swc_next; -}; -TAILQ_HEAD(switch_clients, switch_client); - -struct switchd { - struct privsep sc_ps; - struct switch_server sc_server; - int sc_tap; - struct switch_head sc_switches; - uint32_t sc_swid; - unsigned int sc_cache_max; - unsigned int sc_cache_timeout; - char sc_conffile[PATH_MAX]; - uint8_t sc_opts; - struct switch_clients sc_clients; - struct switch_connections - sc_conns; -}; - -struct ofp_callback { - uint8_t cb_type; - int (*cb)(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); - int (*validate)(struct switchd *, struct sockaddr_storage *, - struct sockaddr_storage *, struct ofp_header *, - struct ibuf *); -}; - -#define SWITCHD_OPT_VERBOSE 0x01 -#define SWITCHD_OPT_NOACTION 0x04 - -struct oflowmod_ctx { - uint8_t ctx_flags; -#define OFMCTX_IBUF 0x01 - enum oflowmod_state ctx_state; - - struct ibuf *ctx_ibuf; - struct ofp_flow_mod *ctx_fm; - size_t ctx_start; - size_t ctx_ostart; - size_t ctx_oend; - size_t ctx_istart; - size_t ctx_iend; - size_t ctx_oioff; - struct ofp_instruction *ctx_oi; -}; - -/* switchd.c */ -int switchd_socket(struct sockaddr *, int); -int switchd_listen(struct sockaddr *); -int switchd_sockaddr(const char *, in_port_t, struct sockaddr_storage *); -int switchd_tap(void); -int switchd_open_device(struct privsep *, const char *, size_t); -struct switch_connection * - switchd_connbyid(struct switchd *, unsigned int, unsigned int); -struct switch_connection * - switchd_connbyaddr(struct switchd *, struct sockaddr *); - -/* packet.c */ -int packet_ether_input(struct ibuf *, size_t, struct packet *); -int packet_input(struct switchd *, struct switch_control *, - uint32_t, uint32_t *, struct packet *); - -/* switch.c */ -void switch_init(struct switchd *); -int switch_dispatch_control(int, struct privsep_proc *, - struct imsg *); -struct switch_control - *switch_add(struct switch_connection *); -void switch_remove(struct switchd *, struct switch_control *); -struct switch_control - *switch_get(struct switch_connection *); -struct macaddr *switch_learn(struct switchd *, struct switch_control *, - uint8_t *, uint32_t); -struct macaddr *switch_cached(struct switch_control *, uint8_t *); -RB_PROTOTYPE(switch_head, switch_control, sw_entry, switch_cmp); -RB_PROTOTYPE(macaddr_head, macaddr, mac_entry, switch_maccmp); - -/* timer.c */ -void timer_set(struct switchd *, struct timer *, - void (*)(struct switchd *, void *), void *); -void timer_add(struct switchd *, struct timer *, int); -void timer_del(struct switchd *, struct timer *); - -/* util.c */ -void socket_set_blockmode(int, enum blockmodes); -int accept4_reserve(int, struct sockaddr *, socklen_t *, - int, int, volatile int *); -in_port_t socket_getport(struct sockaddr_storage *); -int socket_setport(struct sockaddr_storage *, in_port_t); -int sockaddr_cmp(struct sockaddr *, struct sockaddr *, int); -struct in6_addr *prefixlen2mask6(uint8_t, uint32_t *); -uint32_t prefixlen2mask(uint8_t); -const char *print_host(struct sockaddr_storage *, char *, size_t); -const char *print_ether(const uint8_t *) - __attribute__ ((__bounded__(__minbytes__,1,ETHER_ADDR_LEN))); -const char *print_map(unsigned int, struct constmap *); -void print_verbose(const char *emsg, ...) - __attribute__((__format__ (printf, 1, 2))); -void print_debug(const char *emsg, ...) - __attribute__((__format__ (printf, 1, 2))); -void print_hex(uint8_t *, off_t, size_t); -void getmonotime(struct timeval *); -int parsehostport(const char *, struct sockaddr *, socklen_t); - -/* ofrelay.c */ -void ofrelay(struct privsep *, struct privsep_proc *); -void ofrelay_run(struct privsep *, struct privsep_proc *, void *); -int ofrelay_attach(struct switch_server *, int, - struct sockaddr *); -void ofrelay_close(struct switch_connection *); -void ofrelay_write(struct switch_connection *, struct ibuf *); - -/* ofp.c */ -void ofp(struct privsep *, struct privsep_proc *); -void ofp_close(struct switch_connection *); -int ofp_open(struct privsep *, struct switch_connection *); -void ofp_accept(int, short, void *); -int ofp_input(struct switch_connection *, struct ibuf *); -int ofp_nextstate(struct switchd *, struct switch_connection *, - enum ofp_state); -struct switch_table * - switch_tablelookup(struct switch_connection *, int); -struct switch_table * - switch_newtable(struct switch_connection *, int); -void switch_deltable(struct switch_connection *, - struct switch_table *); -void switch_freetables(struct switch_connection *); - -/* ofp10.c */ -int ofp10_hello(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp10_validate(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp10_input(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); - -/* ofp13.c */ -int ofp13_input(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp13_hello(struct switchd *, struct switch_connection *, - struct ofp_header *oh, struct ibuf *); -int ofp13_validate(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp13_desc(struct switchd *, struct switch_connection *); -int ofp13_flow_stats(struct switchd *, struct switch_connection *, - uint32_t, uint32_t, uint8_t); -int ofp13_table_features(struct switchd *, - struct switch_connection *, uint8_t); -int ofp13_featuresrequest(struct switchd *, - struct switch_connection *); -struct ofp_flow_mod * - ofp13_flowmod(struct switch_connection *, struct ibuf *, - uint8_t); -int ofp13_setconfig(struct switchd *, struct switch_connection *, - uint16_t, uint16_t); -int ofp13_tablemiss_sendctrl(struct switchd *, - struct switch_connection *, uint8_t); - -/* ofp_common.c */ -int ofp_validate_header(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, uint8_t); -int ofp_validate(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *, uint8_t); -int ofp_output(struct switch_connection *, struct ofp_header *, - struct ibuf *); -struct multipart_message * - ofp_multipart_lookup(struct switch_connection *, uint32_t); -int ofp_multipart_add(struct switch_connection *, uint32_t, - uint8_t); -void ofp_multipart_del(struct switch_connection *, uint32_t); -void ofp_multipart_free(struct switch_connection *, - struct multipart_message *); -void ofp_multipart_clear(struct switch_connection *); -int action_new(struct ibuf *, uint16_t); -int action_group(struct ibuf *, uint32_t); -int action_output(struct ibuf *, uint32_t, uint16_t); -int action_push(struct ibuf *, uint16_t, uint16_t); -int action_pop_vlan(struct ibuf *); -int action_pop_mpls(struct ibuf *, uint16_t); -int action_copyttlout(struct ibuf *); -int action_copyttlin(struct ibuf *); -int action_decnwttl(struct ibuf *); -struct ofp_action_set_field * - action_setfield(struct ibuf *ibuf); -struct ofp_ox_match * - oxm_get(struct ibuf *, uint16_t, int, uint8_t); -int oxm_inport(struct ibuf *, uint32_t); -int oxm_inphyport(struct ibuf *, uint32_t); -int oxm_metadata(struct ibuf *, int, uint64_t, uint64_t); -int oxm_etheraddr(struct ibuf *, int, uint8_t *, uint8_t *); -int oxm_ethertype(struct ibuf *, uint16_t); -int oxm_vlanvid(struct ibuf *, int, uint16_t, uint16_t); -int oxm_vlanpcp(struct ibuf *, uint8_t); -int oxm_ipdscp(struct ibuf *, uint8_t); -int oxm_ipecn(struct ibuf *, uint8_t); -int oxm_ipproto(struct ibuf *, uint8_t); -int oxm_ipaddr(struct ibuf *, int, int, uint32_t, uint32_t); -int oxm_tcpport(struct ibuf *, int, uint16_t); -int oxm_udpport(struct ibuf *, int, uint16_t); -int oxm_sctpport(struct ibuf *, int, uint16_t); -int oxm_icmpv4type(struct ibuf *, uint8_t); -int oxm_icmpv4code(struct ibuf *, uint8_t); -int oxm_arpop(struct ibuf *, uint16_t); -int oxm_arpaddr(struct ibuf *, int, int, uint32_t, uint32_t); -int oxm_arphaddr(struct ibuf *, int, uint8_t *, uint8_t *); -int oxm_ipv6addr(struct ibuf *, int, struct in6_addr *, - struct in6_addr *); -int oxm_ipv6flowlabel(struct ibuf *, int, uint32_t, uint32_t); -int oxm_icmpv6type(struct ibuf *, uint8_t); -int oxm_icmpv6code(struct ibuf *, uint8_t); -int oxm_ipv6ndtarget(struct ibuf *, struct in6_addr *); -int oxm_ipv6ndlinkaddr(struct ibuf *, int, uint8_t *); -int oxm_mplslabel(struct ibuf *, uint32_t); -int oxm_mplstc(struct ibuf *, uint8_t); -int oxm_mplsbos(struct ibuf *, uint8_t); -int oxm_tunnelid(struct ibuf *, int, uint64_t, uint64_t); -int oxm_ipv6exthdr(struct ibuf *, int, uint16_t, uint16_t); -struct ofp_instruction * - ofp_instruction(struct ibuf *, uint16_t, uint16_t); -struct ibuf * - oflowmod_open(struct oflowmod_ctx *, - struct switch_connection *, struct ibuf *, uint8_t); -int oflowmod_close(struct oflowmod_ctx *); -int oflowmod_mopen(struct oflowmod_ctx *); -int oflowmod_mclose(struct oflowmod_ctx *); -int oflowmod_iopen(struct oflowmod_ctx *); -int oflowmod_iclose(struct oflowmod_ctx *); -int oflowmod_instruction(struct oflowmod_ctx *, unsigned int); - -int oflowmod_instructionclose(struct oflowmod_ctx *); -int oflowmod_state(struct oflowmod_ctx *, - unsigned int, unsigned int); -int oflowmod_err(struct oflowmod_ctx *, const char *, int); -int ofp_validate_hello(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); -int ofp_recv_hello(struct switchd *, struct switch_connection *, - struct ofp_header *, struct ibuf *); -int ofp_send_hello(struct switchd *, struct switch_connection *, - int); -int ofp_send_featuresrequest(struct switchd *, - struct switch_connection *); -/* ofcconn.c */ -void ofcconn(struct privsep *, struct privsep_proc *); -void ofcconn_shutdown(void); - -/* imsg_util.c */ -struct ibuf *ibuf_new(void *, size_t); -struct ibuf *ibuf_static(void); -int ibuf_cat(struct ibuf *, struct ibuf *); -void ibuf_release(struct ibuf *); -size_t ibuf_length(struct ibuf *); -int ibuf_setsize(struct ibuf *, size_t); -int ibuf_setmax(struct ibuf *, size_t); -uint8_t *ibuf_data(struct ibuf *); -void *ibuf_getdata(struct ibuf *, size_t); -ssize_t ibuf_dataleft(struct ibuf *); -size_t ibuf_dataoffset(struct ibuf *); -struct ibuf *ibuf_get(struct ibuf *, size_t); -struct ibuf *ibuf_dup(struct ibuf *); -struct ibuf *ibuf_random(size_t); -int ibuf_prepend(struct ibuf *, void *, size_t); -void *ibuf_advance(struct ibuf *, size_t); -void ibuf_zero(struct ibuf *); -void ibuf_reset(struct ibuf *); - -/* parse.y */ -int cmdline_symset(char *); -int parse_config(const char *, struct switchd *); - -#endif /* SWITCHD_H */ diff --git a/usr.sbin/switchd/timer.c b/usr.sbin/switchd/timer.c deleted file mode 100644 index a21726071bf..00000000000 --- a/usr.sbin/switchd/timer.c +++ /dev/null @@ -1,73 +0,0 @@ -/* $OpenBSD: timer.c,v 1.1 2016/07/19 16:54:26 reyk Exp $ */ - -/* - * Copyright (c) 2010-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" - -void timer_callback(int, short, void *); - -void -timer_set(struct switchd *sc, struct timer *tmr, - void (*cb)(struct switchd *, void *), void *arg) -{ - tmr->tmr_sc = sc; - tmr->tmr_cb = cb; - tmr->tmr_cbarg = arg; - evtimer_set(&tmr->tmr_ev, timer_callback, tmr); -} - -void -timer_add(struct switchd *sc, struct timer *tmr, int timeout) -{ - struct timeval tv = { timeout }; - - if (evtimer_initialized(&tmr->tmr_ev) && - evtimer_pending(&tmr->tmr_ev, NULL)) - evtimer_del(&tmr->tmr_ev); - - evtimer_add(&tmr->tmr_ev, &tv); -} - -void -timer_del(struct switchd *sc, struct timer *tmr) -{ - if (tmr->tmr_sc == sc && tmr->tmr_cb && - evtimer_initialized(&tmr->tmr_ev)) - evtimer_del(&tmr->tmr_ev); -} - -void -timer_callback(int fd, short event, void *arg) -{ - struct timer *tmr = arg; - - if (tmr->tmr_cb) - tmr->tmr_cb(tmr->tmr_sc, tmr->tmr_cbarg); -} diff --git a/usr.sbin/switchd/types.h b/usr.sbin/switchd/types.h deleted file mode 100644 index 569c0709ba1..00000000000 --- a/usr.sbin/switchd/types.h +++ /dev/null @@ -1,109 +0,0 @@ -/* $OpenBSD: types.h,v 1.12 2021/01/27 07:21:54 deraadt Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef SWITCHD_TYPES_H -#define SWITCHD_TYPES_H - -#ifndef SWITCHD_USER -#define SWITCHD_USER "_switchd" -#endif - -#define SWITCHD_NAME "switch" - -#ifndef SWITCHD_CONFIG -#define SWITCHD_CONFIG "/etc/" SWITCHD_NAME "d.conf" -#endif -#define SWITCHD_SOCKET "/var/run/" SWITCHD_NAME "d.sock" - -#define SWITCHD_FD_RESERVE 5 -#define SWITCHD_CYCLE_BUFFERS 8 /* # of static buffers for mapping */ -#define SWITCHD_READ_BUFFER 0xffff -#define SWITCHD_MSGBUF_MAX 0xffff -#define SWITCHD_MAX_TAP 256 -#define SWITCHD_MAX_SESSIONS 0xffff - -#define SWITCHD_CTLR_PORT 6653 /* Assigned by IANA for OpenFlow */ - -#define SWITCHD_CACHE_MAX 4096 /* Default MAC address cache limit */ -#define SWITCHD_CACHE_TIMEOUT 240 /* t/o in seconds for learned MACs */ - -#define SWITCHD_CONNECT_TIMEOUT 5 - -#ifndef ETHER_ADDR_LEN -#define ETHER_ADDR_LEN 6 -#endif - -enum imsg_type { - IMSG_NONE = 0, - IMSG_CTL_VERBOSE, - IMSG_CTL_PROCFD, - IMSG_CTL_NOTIFY, - IMSG_CTL_OK, - IMSG_CTL_FAIL, - IMSG_CTL_END, - IMSG_CTL_RELOAD, - IMSG_CTL_RESET, - IMSG_CTL_SWITCH, - IMSG_CTL_MAC, - IMSG_CTL_SHOW_SUM, - IMSG_CTL_CONNECT, - IMSG_CTL_DISCONNECT, - IMSG_TAPFD -}; - -enum privsep_procid { - PROC_PARENT = 0, - PROC_OFP, - PROC_CONTROL, - PROC_OFCCONN, - PROC_MAX -}; -extern enum privsep_procid privsep_process; - -enum blockmodes { - BM_NORMAL, - BM_NONBLOCK -}; - -enum flushmode { - RESET_RELOAD = 0, - RESET_ALL -}; - -enum switch_conn_type { - SWITCH_CONN_LOCAL, - SWITCH_CONN_TCP, - SWITCH_CONN_TLS -}; - -enum oflowmod_state { - OFMCTX_INIT, - OFMCTX_OPEN, - OFMCTX_MOPEN, - OFMCTX_MCLOSE, - OFMCTX_IOPEN, - OFMCTX_ICLOSE, - OFMCTX_CLOSE, - OFMCTX_ERR -}; - -#ifndef nitems -#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) -#endif - -#endif /* SWITCHD_TYPES_H */ diff --git a/usr.sbin/switchd/util.c b/usr.sbin/switchd/util.c deleted file mode 100644 index d53e674ecf4..00000000000 --- a/usr.sbin/switchd/util.c +++ /dev/null @@ -1,395 +0,0 @@ -/* $OpenBSD: util.c,v 1.6 2017/01/09 14:49:22 reyk Exp $ */ - -/* - * Copyright (c) 2013-2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "switchd.h" - -void -socket_set_blockmode(int fd, enum blockmodes bm) -{ - int flags; - - if ((flags = fcntl(fd, F_GETFL, 0)) == -1) - fatal("fcntl F_GETFL"); - - if (bm == BM_NONBLOCK) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if ((flags = fcntl(fd, F_SETFL, flags)) == -1) - fatal("fcntl F_SETFL"); -} - -int -accept4_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, - int flags, int reserve, volatile int *counter) -{ - int fd; - - if (getdtablecount() + reserve + *counter >= getdtablesize()) { - errno = EMFILE; - return (-1); - } - - if ((fd = accept4(sockfd, addr, addrlen, flags)) != -1) { - (*counter)++; - DPRINTF("%s: inflight incremented, now %d",__func__, *counter); - } - - return (fd); -} - -in_port_t -socket_getport(struct sockaddr_storage *ss) -{ - switch (ss->ss_family) { - case AF_INET: - return (ntohs(((struct sockaddr_in *)ss)->sin_port)); - case AF_INET6: - return (ntohs(((struct sockaddr_in6 *)ss)->sin6_port)); - default: - return (0); - } - - /* NOTREACHED */ - return (0); -} - -int -socket_setport(struct sockaddr_storage *ss, in_port_t port) -{ - switch (ss->ss_family) { - case AF_INET: - ((struct sockaddr_in *)ss)->sin_port = ntohs(port); - return (0); - case AF_INET6: - ((struct sockaddr_in6 *)ss)->sin6_port = ntohs(port); - return (0); - default: - return (-1); - } - - /* NOTREACHED */ - return (-1); -} - -int -sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) -{ - struct sockaddr_in *a4, *b4; - struct sockaddr_in6 *a6, *b6; - struct sockaddr_un *au, *bu; - uint32_t av[4], bv[4], mv[4]; - - if (a->sa_family == AF_UNSPEC || b->sa_family == AF_UNSPEC) - return (0); - else if (a->sa_family > b->sa_family) - return (1); - else if (a->sa_family < b->sa_family) - return (-1); - - if (prefixlen == -1) - memset(&mv, 0xff, sizeof(mv)); - - switch (a->sa_family) { - case AF_INET: - a4 = (struct sockaddr_in *)a; - b4 = (struct sockaddr_in *)b; - - av[0] = a4->sin_addr.s_addr; - bv[0] = b4->sin_addr.s_addr; - if (prefixlen != -1) - mv[0] = prefixlen2mask(prefixlen); - - if ((av[0] & mv[0]) > (bv[0] & mv[0])) - return (1); - if ((av[0] & mv[0]) < (bv[0] & mv[0])) - return (-1); - break; - case AF_INET6: - a6 = (struct sockaddr_in6 *)a; - b6 = (struct sockaddr_in6 *)b; - - memcpy(&av, &a6->sin6_addr.s6_addr, 16); - memcpy(&bv, &b6->sin6_addr.s6_addr, 16); - if (prefixlen != -1) - prefixlen2mask6(prefixlen, mv); - - if ((av[3] & mv[3]) > (bv[3] & mv[3])) - return (1); - if ((av[3] & mv[3]) < (bv[3] & mv[3])) - return (-1); - if ((av[2] & mv[2]) > (bv[2] & mv[2])) - return (1); - if ((av[2] & mv[2]) < (bv[2] & mv[2])) - return (-1); - if ((av[1] & mv[1]) > (bv[1] & mv[1])) - return (1); - if ((av[1] & mv[1]) < (bv[1] & mv[1])) - return (-1); - if ((av[0] & mv[0]) > (bv[0] & mv[0])) - return (1); - if ((av[0] & mv[0]) < (bv[0] & mv[0])) - return (-1); - break; - case AF_UNIX: - au = (struct sockaddr_un *)a; - bu = (struct sockaddr_un *)b; - return (strcmp(au->sun_path, bu->sun_path)); - } - - return (0); -} - -uint32_t -prefixlen2mask(uint8_t prefixlen) -{ - if (prefixlen == 0) - return (0); - - if (prefixlen > 32) - prefixlen = 32; - - return (htonl(0xffffffff << (32 - prefixlen))); -} - -struct in6_addr * -prefixlen2mask6(uint8_t prefixlen, uint32_t *mask) -{ - static struct in6_addr s6; - int i; - - if (prefixlen > 128) - prefixlen = 128; - - bzero(&s6, sizeof(s6)); - for (i = 0; i < prefixlen / 8; i++) - s6.s6_addr[i] = 0xff; - i = prefixlen % 8; - if (i) - s6.s6_addr[prefixlen / 8] = 0xff00 >> i; - - memcpy(mask, &s6, sizeof(s6)); - - return (&s6); -} - -const char * -print_ether(const uint8_t *ea) -{ - static char sbuf[SWITCHD_CYCLE_BUFFERS] - [ETHER_ADDR_LEN * 2 + 5 + 1]; - static int idx = 0; - size_t len; - char *buf; - - buf = sbuf[idx]; - len = sizeof(sbuf[idx]); - if (++idx >= SWITCHD_CYCLE_BUFFERS) - idx = 0; - - snprintf(buf, len, "%02x:%02x:%02x:%02x:%02x:%02x", - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); - - return (buf); -} - -const char * -print_host(struct sockaddr_storage *ss, char *buf, size_t len) -{ - static char sbuf[SWITCHD_CYCLE_BUFFERS][NI_MAXHOST + 7]; - struct sockaddr_un *un; - static int idx = 0; - char pbuf[7]; - in_port_t port; - - if (buf == NULL) { - buf = sbuf[idx]; - len = sizeof(sbuf[idx]); - if (++idx >= SWITCHD_CYCLE_BUFFERS) - idx = 0; - } - - if (ss->ss_family == AF_UNSPEC) { - strlcpy(buf, "any", len); - return (buf); - } else if (ss->ss_family == AF_UNIX) { - un = (struct sockaddr_un *)ss; - strlcpy(buf, un->sun_path, len); - return (buf); - } - - if (getnameinfo((struct sockaddr *)ss, ss->ss_len, - buf, len, NULL, 0, NI_NUMERICHOST) != 0) { - buf[0] = '\0'; - return (NULL); - } - - if ((port = socket_getport(ss)) != 0) { - snprintf(pbuf, sizeof(pbuf), ":%d", port); - (void)strlcat(buf, pbuf, len); - } - - return (buf); -} - -const char * -print_map(unsigned int type, struct constmap *map) -{ - unsigned int i; - static char buf[SWITCHD_CYCLE_BUFFERS][32]; - static int idx = 0; - const char *name = NULL; - - if (idx >= SWITCHD_CYCLE_BUFFERS) - idx = 0; - bzero(buf[idx], sizeof(buf[idx])); - - for (i = 0; map[i].cm_name != NULL; i++) { - if (map[i].cm_type == type) { - name = map[i].cm_name; - break; - } - } - - if (name == NULL) - snprintf(buf[idx], sizeof(buf[idx]), "<%u>", type); - else - strlcpy(buf[idx], name, sizeof(buf[idx])); - - return (buf[idx++]); -} - -void -getmonotime(struct timeval *tv) -{ - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts)) - fatal("clock_gettime"); - - TIMESPEC_TO_TIMEVAL(tv, &ts); -} - -void -print_debug(const char *emsg, ...) -{ - va_list ap; - - if (log_getverbose() > 2) { - va_start(ap, emsg); - vfprintf(stderr, emsg, ap); - va_end(ap); - } -} - -void -print_verbose(const char *emsg, ...) -{ - va_list ap; - - if (log_getverbose()) { - va_start(ap, emsg); - vfprintf(stderr, emsg, ap); - va_end(ap); - } -} - -void -print_hex(uint8_t *buf, off_t offset, size_t length) -{ - unsigned int i; - - if (log_getverbose() < 3 || !length) - return; - - for (i = 0; i < length; i++) { - if (i && (i % 4) == 0) { - if ((i % 32) == 0) - print_debug("\n"); - else - print_debug(" "); - } - print_debug("%02x", buf[offset + i]); - } - print_debug("\n"); -} - -int -parsehostport(const char *str, struct sockaddr *sa, socklen_t salen) -{ - char buf[NI_MAXHOST + NI_MAXSERV + 8], *servp, *nodep; - struct addrinfo hints, *ai; - - if (strlcpy(buf, str, sizeof(buf)) >= sizeof(buf)) - return (-1); - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = 0; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - if (buf[0] == '[' && - (servp = strchr(buf, ']')) != NULL && - (*(servp + 1) == '\0' || *(servp + 1) == ':')) { - hints.ai_family = AF_INET6; - hints.ai_flags = AI_NUMERICHOST; - nodep = buf + 1; - *servp++ = '\0'; - } else { - nodep = buf; - servp = strrchr(nodep, ':'); - } - if (servp != NULL) { - *servp = '\0'; - servp++; - } else - servp = NULL; - - if (getaddrinfo(nodep, servp, &hints, &ai) != 0) - return (-1); - - if (salen < ai->ai_addrlen) { - freeaddrinfo(ai); - return (-1); - } - memset(sa, 0, salen); - memcpy(sa, ai->ai_addr, ai->ai_addrlen); - - return (0); -}