/* * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. * * 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. */ #include #include "tc.h" #include #include "netlink-socket.h" #include "netlink.h" #include "openvswitch/ofpbuf.h" #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(tc); /* Returns tc handle 'major':'minor'. */ unsigned int tc_make_handle(unsigned int major, unsigned int minor) { return TC_H_MAKE(major << 16, minor); } /* Returns the major number from 'handle'. */ unsigned int tc_get_major(unsigned int handle) { return TC_H_MAJ(handle) >> 16; } /* Returns the minor number from 'handle'. */ unsigned int tc_get_minor(unsigned int handle) { return TC_H_MIN(handle); } struct tcmsg * tc_make_request(int ifindex, int type, unsigned int flags, struct ofpbuf *request) { struct tcmsg *tcmsg; ofpbuf_init(request, 512); nl_msg_put_nlmsghdr(request, sizeof *tcmsg, type, NLM_F_REQUEST | flags); tcmsg = ofpbuf_put_zeros(request, sizeof *tcmsg); tcmsg->tcm_family = AF_UNSPEC; tcmsg->tcm_ifindex = ifindex; /* Caller should fill in tcmsg->tcm_handle. */ /* Caller should fill in tcmsg->tcm_parent. */ return tcmsg; } int tc_transact(struct ofpbuf *request, struct ofpbuf **replyp) { int error = nl_transact(NETLINK_ROUTE, request, replyp); ofpbuf_uninit(request); return error; } /* Adds or deletes a root ingress qdisc on device with specified ifindex. * * This function is equivalent to running the following when 'add' is true: * /sbin/tc qdisc add dev handle ffff: ingress * * This function is equivalent to running the following when 'add' is false: * /sbin/tc qdisc del dev handle ffff: ingress * * Where dev is the device with specified ifindex name. * * The configuration and stats may be seen with the following command: * /sbin/tc -s qdisc show dev * * Returns 0 if successful, otherwise a positive errno value. */ int tc_add_del_ingress_qdisc(int ifindex, bool add) { struct ofpbuf request; struct tcmsg *tcmsg; int error; int type = add ? RTM_NEWQDISC : RTM_DELQDISC; int flags = add ? NLM_F_EXCL | NLM_F_CREATE : 0; tcmsg = tc_make_request(ifindex, type, flags, &request); tcmsg->tcm_handle = tc_make_handle(0xffff, 0); tcmsg->tcm_parent = TC_H_INGRESS; nl_msg_put_string(&request, TCA_KIND, "ingress"); nl_msg_put_unspec(&request, TCA_OPTIONS, NULL, 0); error = tc_transact(&request, NULL); if (error) { /* If we're deleting the qdisc, don't worry about some of the * error conditions. */ if (!add && (error == ENOENT || error == EINVAL)) { return 0; } return error; } return 0; }