* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <errno.h>
+#include <string.h>
#include <sys/queue.h>
#include <rte_byteorder.h>
}
err = nl_recv_ack(pmd->nlsk_fd);
if (err < 0) {
+ RTE_LOG(ERR, PMD,
+ "Kernel refused TC filter rule creation (%d): %s\n",
+ errno, strerror(errno));
rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_HANDLE,
NULL, "overlapping rules");
goto fail;
}
err = nl_recv_ack(pmd->nlsk_fd);
if (err < 0) {
+ RTE_LOG(ERR, PMD,
+ "Kernel refused TC filter rule creation (%d): %s\n",
+ errno, strerror(errno));
rte_flow_error_set(
error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
NULL, "overlapping rules");
goto end;
}
ret = nl_recv_ack(pmd->nlsk_fd);
+ /* If errno is ENOENT, the rule is already no longer in the kernel. */
+ if (ret < 0 && errno == ENOENT)
+ ret = 0;
if (ret < 0) {
+ RTE_LOG(ERR, PMD,
+ "Kernel refused TC filter rule deletion (%d): %s\n",
+ errno, strerror(errno));
rte_flow_error_set(
error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"couldn't receive kernel ack to our request");
goto end;
}
ret = nl_recv_ack(pmd->nlsk_fd);
+ if (ret < 0 && errno == ENOENT)
+ ret = 0;
if (ret < 0) {
+ RTE_LOG(ERR, PMD,
+ "Kernel refused TC filter rule deletion (%d): %s\n",
+ errno, strerror(errno));
rte_flow_error_set(
error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
NULL, "Failure trying to receive nl ack");
err = nl_recv_ack(pmd->nlsk_fd);
if (err < 0) {
RTE_LOG(ERR, PMD,
- "Kernel refused TC filter rule creation");
+ "Kernel refused TC filter rule creation (%d): %s\n",
+ errno, strerror(errno));
goto fail;
}
LIST_INSERT_HEAD(&pmd->implicit_flows, remote_flow, next);
* The netlink socket file descriptor used for communication.
*
* @return
- * 0 on success, -1 otherwise.
+ * 0 on success, -1 otherwise with errno set.
*/
int
nl_recv_ack(int nlsk_fd)
* Custom arguments for the callback.
*
* @return
- * 0 on success, -1 otherwise.
+ * 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;
- struct nlmsghdr *nh;
char buf[BUF_SIZE];
struct iovec iov = {
.iov_base = buf,
.msg_name = &sa,
.msg_namelen = sizeof(sa),
.msg_iov = &iov,
+ /* One message at a time */
.msg_iovlen = 1,
};
- int recv_bytes = 0, done = 0, multipart = 0, error = 0;
+ int multipart = 0;
+ int ret = 0;
-read:
- 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)) {
- /*
- * Multi-part messages and their following DONE message have the
- * NLM_F_MULTI flag set. Make note, in order to read the DONE
- * message afterwards.
- */
- if (nh->nlmsg_flags & NLM_F_MULTI)
- multipart = 1;
- if (nh->nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *err_data = NLMSG_DATA(nh);
+ 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)
- RTE_LOG(DEBUG, PMD, "%s() ack message recvd\n",
- __func__);
- else {
- RTE_LOG(DEBUG, PMD,
- "%s() error message recvd\n", __func__);
- error = 1;
+ 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);
}
- /* The end of multipart message. */
- if (nh->nlmsg_type == NLMSG_DONE)
- /* No need to call the callback for a DONE message. */
- done = 1;
- else if (cb)
- if (cb(nh, arg) < 0)
- error = 1;
- }
- if (multipart && !done)
- goto read;
- if (error)
- return -1;
- return 0;
+ } while (multipart);
+ return ret;
}
/**
* Additional info to identify the QDISC (handle and parent).
*
* @return
- * 0 on success, -1 otherwise.
+ * 0 on success, -1 otherwise with errno set.
*/
static int
qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
fd = nlsk_fd;
}
if (nl_send(fd, &msg.nh) < 0)
- return -1;
+ goto error;
if (nl_recv_ack(fd) < 0)
- return -1;
+ goto error;
if (!nlsk_fd)
return nl_final(fd);
return 0;
+error:
+ if (!nlsk_fd)
+ nl_final(fd);
+ return -1;
}
/**
* The netdevice ifindex where to add the multiqueue QDISC.
*
* @return
- * -1 if the qdisc cannot be added, and 0 otherwise.
+ * 0 on success, -1 otherwise with errno set.
*/
int
qdisc_add_multiq(int nlsk_fd, uint16_t ifindex)
* The netdevice ifindex where the QDISC will be added.
*
* @return
- * -1 if the qdisc cannot be added, and 0 otherwise.
+ * 0 on success, -1 otherwise with errno set.
*/
int
qdisc_add_ingress(int nlsk_fd, uint16_t ifindex)
return 0;
}
-/**
- * Callback function to check for QDISC existence.
- * If the QDISC is found to exist, increment "exists" in the custom arg.
- *
- * @param[in] nh
- * The netlink message to parse, received from the kernel.
- * @param[in, out] arg
- * Custom arguments for the callback.
- *
- * @return
- * 0.
- */
-static int
-qdisc_exist_cb(struct nlmsghdr *nh, void *arg)
-{
- struct list_args *args = (struct list_args *)arg;
- struct qdisc_custom_arg *custom = args->custom_arg;
- struct tcmsg *t = NLMSG_DATA(nh);
-
- /* filter by request iface */
- if (args->ifindex != (unsigned int)t->tcm_ifindex)
- return 0;
- if (t->tcm_handle != custom->handle || t->tcm_parent != custom->parent)
- return 0;
- custom->exists++;
- return 0;
-}
-
/**
* Callback function to delete a QDISC.
*
* Custom arguments for the callback.
*
* @return
- * 0.
+ * 0 on success, -1 otherwise with errno set.
*/
static int
qdisc_del_cb(struct nlmsghdr *nh, void *arg)
* The arguments to provide the callback function with.
*
* @return
- * -1 if either sending the netlink message failed, or if receiving the answer
- * failed, or finally if the callback returned a negative value for that
- * answer.
- * 0 is returned otherwise.
+ * 0 on success, -1 otherwise with errno set.
*/
static int
qdisc_iterate(int nlsk_fd, uint16_t ifindex,
return 0;
}
-/**
- * Check whether a given QDISC already exists for the netdevice.
- *
- * @param[in] nlsk_fd
- * The netlink socket file descriptor used for communication.
- * @param[in] ifindex
- * The netdevice ifindex to check QDISC existence for.
- * @param[in] callback
- * The function to call for each QDISC.
- * @param[in, out] arg
- * The arguments to provide the callback function with.
- *
- * @return
- * 1 if the qdisc exists, 0 otherwise.
- */
-int
-qdisc_exists(int nlsk_fd, uint16_t ifindex, uint32_t handle, uint32_t parent)
-{
- struct qdisc_custom_arg arg = {
- .handle = handle,
- .parent = parent,
- .exists = 0,
- };
-
- qdisc_iterate(nlsk_fd, ifindex, qdisc_exist_cb, &arg);
- if (arg.exists)
- return 1;
- return 0;
-}
-
/**
* Delete all QDISCs for a given netdevice.
*
* The netdevice ifindex where to find QDISCs.
*
* @return
- * -1 if the lookup failed, 0 otherwise.
+ * 0 on success, -1 otherwise with errno set.
*/
int
qdisc_flush(int nlsk_fd, uint16_t ifindex)
int
qdisc_create_multiq(int nlsk_fd, uint16_t ifindex)
{
- if (!qdisc_exists(nlsk_fd, ifindex,
- TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0), TC_H_ROOT)) {
- if (qdisc_add_multiq(nlsk_fd, ifindex) < 0) {
- RTE_LOG(ERR, PMD, "Could not add multiq qdisc\n");
- return -1;
- }
+ int err = 0;
+
+ err = qdisc_add_multiq(nlsk_fd, ifindex);
+ if (err < 0 && errno != -EEXIST) {
+ RTE_LOG(ERR, PMD, "Could not add multiq qdisc (%d): %s\n",
+ errno, strerror(errno));
+ return -1;
}
return 0;
}
int
qdisc_create_ingress(int nlsk_fd, uint16_t ifindex)
{
- if (!qdisc_exists(nlsk_fd, ifindex,
- TC_H_MAKE(TC_H_INGRESS, 0), TC_H_INGRESS)) {
- if (qdisc_add_ingress(nlsk_fd, ifindex) < 0) {
- RTE_LOG(ERR, PMD, "Could not add ingress qdisc\n");
- return -1;
- }
+ int err = 0;
+
+ err = qdisc_add_ingress(nlsk_fd, ifindex);
+ if (err < 0 && errno != -EEXIST) {
+ RTE_LOG(ERR, PMD, "Could not add ingress qdisc (%d): %s\n",
+ errno, strerror(errno));
+ return -1;
}
return 0;
}
void tc_init_msg(struct nlmsg *msg, uint16_t ifindex, uint16_t type,
uint16_t flags);
-int qdisc_exists(int nlsk_fd, uint16_t ifindex, uint32_t handle,
- uint32_t parent);
int qdisc_list(int nlsk_fd, uint16_t ifindex);
int qdisc_flush(int nlsk_fd, uint16_t ifindex);
int qdisc_create_ingress(int nlsk_fd, uint16_t ifindex);