+++ /dev/null
-# $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 '<net/ofp.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 <bsd.prog.mk>
+++ /dev/null
-/* $OpenBSD: ofpclient.c,v 1.7 2018/10/21 21:10:24 akoshibe Exp $ */
-
-/*
- * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/queue.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/tree.h>
-#include <sys/un.h>
-
-#include <net/if.h>
-#include <net/ofp.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <errno.h>
-#include <event.h>
-#include <fcntl.h>
-#include <string.h>
-#include <ctype.h>
-#include <poll.h>
-#include <err.h>
-#include <pwd.h>
-#include <vis.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: parser.c,v 1.10 2018/10/21 21:10:24 akoshibe Exp $ */
-
-/*
- * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
- * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
-#include <sys/un.h>
-
-#include <err.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <event.h>
-#include <netdb.h>
-
-#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, " <cr>\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, " <port>\n");
- break;
- case PATH:
- fprintf(stderr, " <path>\n");
- break;
- case ADDRESS:
- fprintf(stderr, " <address>\n");
- break;
- case TABLE:
- fprintf(stderr, " <table>\n");
- break;
- case URI:
- fprintf(stderr, " <uri>\n");
- break;
- case ENDTOKEN:
- break;
- }
- }
-
- if (level == 0 && table[0].type == NOTOKEN && table[0].next)
- return (show_valid_args(table[0].next, 1));
-}
+++ /dev/null
-/* $OpenBSD: parser.h,v 1.4 2016/11/24 09:23:11 reyk Exp $ */
-
-/*
- * Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 */
+++ /dev/null
-.\" $OpenBSD: switchctl.8,v 1.6 2018/10/21 21:10:24 akoshibe Exp $
-.\"
-.\" Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org>
-.\"
-.\" 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 .
+++ /dev/null
-/* $OpenBSD: switchctl.c,v 1.9 2018/10/24 18:06:21 akoshibe Exp $ */
-
-/*
- * Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
- * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
- * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <sys/un.h>
-#include <sys/tree.h>
-
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <event.h>
-#include <pwd.h>
-
-#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, "<unknown>", 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);
-}
+++ /dev/null
-# $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 '<net/ofp.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 <bsd.prog.mk>
+++ /dev/null
-/* $OpenBSD: control.c,v 1.10 2021/04/20 21:11:56 dv Exp $ */
-
-/*
- * Copyright (c) 2010-2016 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
- *
- * 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 <sys/queue.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/tree.h>
-
-#include <net/if.h>
-
-#include <errno.h>
-#include <event.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <imsg.h>
-
-#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);
-}
+++ /dev/null
-#!/bin/sh
-# $OpenBSD: genmap.sh,v 1.6 2016/11/18 16:49:35 reyk Exp $
-
-# Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
-#
-# 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 <<EOF
-/* Automatically generated from ${FILE}, do not edit */
-EOF
-sed -n '1,/^ \*\//p' $INPUT
-cat <<EOF
-
-#include <sys/types.h>
-${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
+++ /dev/null
-/* $OpenBSD: imsg_util.c,v 1.5 2016/09/30 11:57:57 reyk Exp $ */
-
-/*
- * Copyright (c) 2010-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-
-#include <net/if.h>
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <event.h>
-#include <imsg.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: log.c,v 1.5 2017/03/21 12:06:56 bluhm Exp $ */
-
-/*
- * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <syslog.h>
-#include <errno.h>
-#include <time.h>
-
-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);
-}
+++ /dev/null
-/* $OpenBSD: ofcconn.c,v 1.13 2019/06/28 13:32:51 deraadt Exp $ */
-
-/*
- * Copyright (c) 2016 YASUOKA Masahiko <yasuoka@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <net/ofp.h>
-
-#include <errno.h>
-#include <event.h>
-#include <imsg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <imsg.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: ofp.c,v 1.18 2016/12/22 15:31:43 rzalamena Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <sys/queue.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <net/ofp.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <event.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: ofp10.c,v 1.21 2019/05/05 21:33:00 akoshibe Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ofp.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <netinet/tcp.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <imsg.h>
-#include <event.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: ofp10.h,v 1.2 2016/09/30 12:48:27 reyk Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <net/ofp.h>
-
-/* 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_ */
+++ /dev/null
-/* $OpenBSD: ofp13.c,v 1.47 2019/11/27 17:37:32 akoshibe Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2016 Rafael Zalamena <rzalamena@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ofp.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <netinet/tcp.h>
-#include <netmpls/mpls.h>
-
-#include <endian.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <imsg.h>
-#include <event.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: ofp_common.c,v 1.11 2019/11/21 06:22:57 akoshibe Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2016 Rafael Zalamena <rzalamena@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ofp.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <netinet/tcp.h>
-#include <netmpls/mpls.h>
-
-#include <endian.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <imsg.h>
-#include <event.h>
-
-#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__));
-
-}
+++ /dev/null
-/* $OpenBSD: ofp_map.h,v 1.9 2016/11/18 16:56:09 reyk Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 */
+++ /dev/null
-/* $OpenBSD: ofrelay.c,v 1.10 2016/12/22 15:31:43 rzalamena Exp $ */
-
-/*
- * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <sys/queue.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <errno.h>
-#include <event.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: packet.c,v 1.6 2019/05/05 21:33:00 akoshibe Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <netinet/tcp.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <event.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: parse.y,v 1.16 2021/10/15 15:01:29 naddy Exp $ */
-
-/*
- * Copyright (c) 2007-2016 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
- * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
- * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <limits.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#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 <v.string> STRING
-%token <v.number> NUMBER
-%type <v.number> opttls
-%type <v.conn> optofcconn
-%type <v.port> 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);
-}
+++ /dev/null
-/* $OpenBSD: proc.c,v 1.15 2021/04/20 21:11:56 dv Exp $ */
-
-/*
- * Copyright (c) 2010 - 2016 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <paths.h>
-#include <pwd.h>
-#include <event.h>
-#include <imsg.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: proc.h,v 1.9 2021/04/20 21:11:56 dv Exp $ */
-
-/*
- * Copyright (c) 2010-2015 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <imsg.h>
-#include <event.h>
-#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 */
+++ /dev/null
-/* $OpenBSD: switch.c,v 1.3 2016/09/18 13:17:40 rzalamena Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <imsg.h>
-#include <event.h>
-
-#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);
+++ /dev/null
-.\" $OpenBSD: switchd.8,v 1.4 2016/11/29 07:18:23 jmc Exp $
-.\"
-.\" Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org>
-.\"
-.\" 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 .
+++ /dev/null
-/* $OpenBSD: switchd.c,v 1.20 2021/09/06 13:32:18 deraadt Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <sys/queue.h>
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <syslog.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <pwd.h>
-#include <event.h>
-
-#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);
-}
+++ /dev/null
-.\" $OpenBSD: switchd.conf.5,v 1.10 2019/07/11 09:28:54 sthen Exp $
-.\"
-.\" Copyright (c) 2014, 2015, 2016 Reyk Floeter <reyk@openbsd.org>
-.\" Copyright (c) 2016 YASUOKA Masahiko <yasuoka@openbsd.org>
-.\"
-.\" 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
+++ /dev/null
-/* $OpenBSD: switchd.h,v 1.30 2019/11/21 06:22:57 akoshibe Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/queue.h>
-#include <sys/tree.h>
-#include <sys/uio.h>
-
-#include <net/ofp.h>
-
-#include <limits.h>
-#include <imsg.h>
-
-#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 */
+++ /dev/null
-/* $OpenBSD: timer.c,v 1.1 2016/07/19 16:54:26 reyk Exp $ */
-
-/*
- * Copyright (c) 2010-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <event.h>
-
-#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);
-}
+++ /dev/null
-/* $OpenBSD: types.h,v 1.12 2021/01/27 07:21:54 deraadt Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 */
+++ /dev/null
-/* $OpenBSD: util.c,v 1.6 2017/01/09 14:49:22 reyk Exp $ */
-
-/*
- * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <netinet/tcp.h>
-
-#include <unistd.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <event.h>
-
-#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);
-}