summaryrefslogtreecommitdiffstats
path: root/extras/emacs/plugin-setup-skel.el
blob: 9ff2a7b9427ec5a9c83a303e364e5509af1f55db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
;;; plugin-setup-skel.el - debug CLI + pg setup
;;;
;;; Copyright (c) 2018 Cisco and/or its affiliates.
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at:
;;;
;;;     http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.

(require 'skeleton)

(define-skeleton skel-plugin-setup
"Insert a debug cli / pg skeleton "
nil
'(if (not (boundp 'plugin-name))
     (setq plugin-name (read-string "Plugin name: ")))
'(setq PLUGIN-NAME (upcase plugin-name))
'(setq capital-oh-en "ON")
"
comment { simple debug CLI setup script w/ packet generator test vector }
set term page off
loop create
set int ip address loop0 192.168.1.1/24
set int state loop0 up

comment { Packet generator script. Src MAC 00:de:ad:be:ef:01 }
comment { Dst mac 01:ba:db:ab:be:01 ethtype 0800 }
packet-generator new {
    name simple
    limit 1
    size 128-128
    interface loop0
    node " plugin-name "
    data {
        hex 0x00deadbeef0001badbabbe010800 
        incrementing 30
    }
}
")
teral.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*-
 *   BSD LICENSE
 *
 *   Copyright 2017 6WIND S.A.
 *   Copyright 2017 Mellanox.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of 6WIND S.A. nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <errno.h>
#include <inttypes.h>
#include <linux/netlink.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#include <rte_malloc.h>
#include <tap_netlink.h>
#include <rte_random.h>

/* Must be quite large to support dumping a huge list of QDISC or filters. */
#define BUF_SIZE (32 * 1024) /* Size of the buffer to receive kernel messages */
#define SNDBUF_SIZE 32768 /* Send buffer size for the netlink socket */
#define RCVBUF_SIZE 32768 /* Receive buffer size for the netlink socket */

struct nested_tail {
	struct rtattr *tail;
	struct nested_tail *prev;
};

/**
 * Initialize a netlink socket for communicating with the kernel.
 *
 * @param nl_groups
 *   Set it to a netlink group value (e.g. RTMGRP_LINK) to receive messages for
 *   specific netlink multicast groups. Otherwise, no subscription will be made.
 *
 * @return
 *   netlink socket file descriptor on success, -1 otherwise.
 */
int
nl_init(uint32_t nl_groups)
{
	int fd, sndbuf_size = SNDBUF_SIZE, rcvbuf_size = RCVBUF_SIZE;
	struct sockaddr_nl local = {
		.nl_family = AF_NETLINK,
		.nl_groups = nl_groups,
	};

	fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
	if (fd < 0) {
		RTE_LOG(ERR, PMD, "Unable to create a netlink socket\n");
		return -1;
	}
	if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(int))) {
		RTE_LOG(ERR, PMD, "Unable to set socket buffer send size\n");
		return -1;
	}
	if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, sizeof(int))) {
		RTE_LOG(ERR, PMD, "Unable to set socket buffer receive size\n");
		return -1;
	}
	if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
		RTE_LOG(ERR, PMD, "Unable to bind to the netlink socket\n");
		return -1;
	}
	return fd;
}

/**
 * Clean up a netlink socket once all communicating with the kernel is finished.
 *
 * @param[in] nlsk_fd
 *   The netlink socket file descriptor used for communication.
 *
 * @return
 *   0 on success, -1 otherwise.
 */
int
nl_final(int nlsk_fd)
{
	if (close(nlsk_fd)) {
		RTE_LOG(ERR, PMD, "Failed to close netlink socket: %s (%d)\n",
			strerror(errno), errno);
		return -1;
	}
	return 0;
}

/**
 * Send a message to the kernel on the netlink socket.
 *
 * @param[in] nlsk_fd
 *   The netlink socket file descriptor used for communication.
 * @param[in] nh
 *   The netlink message send to the kernel.
 *
 * @return
 *   the number of sent bytes on success, -1 otherwise.
 */
int
nl_send(int nlsk_fd, struct nlmsghdr *nh)
{
	/* man 7 netlink EXAMPLE */
	struct sockaddr_nl sa = {
		.nl_family = AF_NETLINK,
	};
	struct iovec iov = {
		.iov_base = nh,
		.iov_len = nh->nlmsg_len,
	};
	struct msghdr msg = {
		.msg_name = &sa,
		.msg_namelen = sizeof(sa),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	int send_bytes;

	nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
	nh->nlmsg_seq = (uint32_t)rte_rand();
	send_bytes = sendmsg(nlsk_fd, &msg, 0);
	if (send_bytes < 0) {
		RTE_LOG(ERR, PMD, "Failed to send netlink message: %s (%d)\n",
			strerror(errno), errno);
		return -1;
	}
	return send_bytes;
}

/**
 * Check that the kernel sends an appropriate ACK in response to an nl_send().
 *
 * @param[in] nlsk_fd
 *   The netlink socket file descriptor used for communication.
 *
 * @return
 *   0 on success, -1 otherwise with errno set.
 */
int
nl_recv_ack(int nlsk_fd)
{
	return nl_recv(nlsk_fd, NULL, NULL);
}

/**
 * Receive a message from the kernel on the netlink socket, following an
 * nl_send().
 *
 * @param[in] nlsk_fd
 *   The netlink socket file descriptor used for communication.
 * @param[in] cb
 *   The callback function to call for each netlink message received.
 * @param[in, out] arg
 *   Custom arguments for the callback.
 *
 * @return
 *   0 on success, -1 otherwise with errno set.
 */
int
nl_recv(int nlsk_fd, int (*cb)(struct nlmsghdr *, void *arg), void *arg)
{
	/* man 7 netlink EXAMPLE */
	struct sockaddr_nl sa;
	char buf[BUF_SIZE];
	struct iovec iov = {
		.iov_base = buf,
		.iov_len = sizeof(buf),
	};
	struct msghdr msg = {
		.msg_name = &sa,
		.msg_namelen = sizeof(sa),
		.msg_iov = &iov,
		/* One message at a time */
		.msg_iovlen = 1,
	};
	int multipart = 0;
	int ret = 0;

	do {
		struct nlmsghdr *nh;
		int recv_bytes = 0;

		recv_bytes = recvmsg(nlsk_fd, &msg, 0);
		if (recv_bytes < 0)
			return -1;
		for (nh = (struct nlmsghdr *)buf;
		     NLMSG_OK(nh, (unsigned int)recv_bytes);
		     nh = NLMSG_NEXT(nh, recv_bytes)) {
			if (nh->nlmsg_type == NLMSG_ERROR) {
				struct nlmsgerr *err_data = NLMSG_DATA(nh);

				if (err_data->error < 0) {
					errno = -err_data->error;
					return -1;
				}
				/* Ack message. */
				return 0;
			}
			/* Multi-part msgs and their trailing DONE message. */
			if (nh->nlmsg_flags & NLM_F_MULTI) {
				if (nh->nlmsg_type == NLMSG_DONE)
					return 0;
				multipart = 1;
			}
			if (cb)
				ret = cb(nh, arg);
		}
	} while (multipart);
	return ret;
}

/**
 * Append a netlink attribute to a message.
 *
 * @param[in, out] nh
 *   The netlink message to parse, received from the kernel.
 * @param[in] type
 *   The type of attribute to append.
 * @param[in] data_len
 *   The length of the data to append.
 * @param[in] data
 *   The data to append.
 */
void
nlattr_add(struct nlmsghdr *nh, unsigned short type,
	   unsigned int data_len, const void *data)
{
	/* see man 3 rtnetlink */
	struct rtattr *rta;

	rta = (struct rtattr *)NLMSG_TAIL(nh);
	rta->rta_len = RTA_LENGTH(data_len);
	rta->rta_type = type;
	memcpy(RTA_DATA(rta), data, data_len);
	nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + RTA_ALIGN(rta->rta_len);
}

/**
 * Append a uint8_t netlink attribute to a message.
 *
 * @param[in, out] nh
 *   The netlink message to parse, received from the kernel.
 * @param[in] type
 *   The type of attribute to append.
 * @param[in] data
 *   The data to append.
 */
void
nlattr_add8(struct nlmsghdr *nh, unsigned short type, uint8_t data)
{
	nlattr_add(nh, type, sizeof(uint8_t), &data);
}

/**
 * Append a uint16_t netlink attribute to a message.
 *
 * @param[in, out] nh
 *   The netlink message to parse, received from the kernel.
 * @param[in] type
 *   The type of attribute to append.
 * @param[in] data
 *   The data to append.
 */
void
nlattr_add16(struct nlmsghdr *nh, unsigned short type, uint16_t data)
{
	nlattr_add(nh, type, sizeof(uint16_t), &data);
}

/**
 * Append a uint16_t netlink attribute to a message.
 *
 * @param[in, out] nh
 *   The netlink message to parse, received from the kernel.
 * @param[in] type
 *   The type of attribute to append.
 * @param[in] data
 *   The data to append.
 */
void
nlattr_add32(struct nlmsghdr *nh, unsigned short type, uint32_t data)
{
	nlattr_add(nh, type, sizeof(uint32_t), &data);
}

/**
 * Start a nested netlink attribute.
 * It must be followed later by a call to nlattr_nested_finish().
 *
 * @param[in, out] msg
 *   The netlink message where to edit the nested_tails metadata.
 * @param[in] type
 *   The nested attribute type to append.
 *
 * @return
 *   -1 if adding a nested netlink attribute failed, 0 otherwise.
 */
int
nlattr_nested_start(struct nlmsg *msg, uint16_t type)
{
	struct nested_tail *tail;

	tail = rte_zmalloc(NULL, sizeof(struct nested_tail), 0);
	if (!tail) {
		RTE_LOG(ERR, PMD,
			"Couldn't allocate memory for nested netlink"
			" attribute\n");
		return -1;
	}

	tail->tail = (struct rtattr *)NLMSG_TAIL(&msg->nh);

	nlattr_add(&msg->nh, type, 0, NULL);

	tail->prev = msg->nested_tails;

	msg->nested_tails = tail;

	return 0;
}

/**
 * End a nested netlink attribute.
 * It follows a call to nlattr_nested_start().
 * In effect, it will modify the nested attribute length to include every bytes
 * from the nested attribute start, up to here.
 *
 * @param[in, out] msg
 *   The netlink message where to edit the nested_tails metadata.
 */
void
nlattr_nested_finish(struct nlmsg *msg)
{
	struct nested_tail *tail = msg->nested_tails;

	tail->tail->rta_len = (char *)NLMSG_TAIL(&msg->nh) - (char *)tail->tail;

	if (tail->prev)
		msg->nested_tails = tail->prev;

	rte_free(tail);
}