2017-06-13 18:03:24 +03:00
|
|
|
/*
|
|
|
|
* 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 <config.h>
|
|
|
|
#include "tc.h"
|
|
|
|
#include <errno.h>
|
|
|
|
#include "netlink-socket.h"
|
|
|
|
#include "netlink.h"
|
|
|
|
#include "openvswitch/ofpbuf.h"
|
|
|
|
#include "openvswitch/vlog.h"
|
|
|
|
|
|
|
|
VLOG_DEFINE_THIS_MODULE(tc);
|
|
|
|
|
|
|
|
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 <devname> handle ffff: ingress
|
|
|
|
*
|
|
|
|
* This function is equivalent to running the following when 'add' is false:
|
|
|
|
* /sbin/tc qdisc del dev <devname> handle ffff: ingress
|
|
|
|
*
|
|
|
|
* Where dev <devname> is the device with specified ifindex name.
|
|
|
|
*
|
|
|
|
* The configuration and stats may be seen with the following command:
|
|
|
|
* /sbin/tc -s qdisc show dev <devname>
|
|
|
|
*
|
|
|
|
* 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);
|
2017-06-13 18:03:25 +03:00
|
|
|
tcmsg->tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
|
2017-06-13 18:03:24 +03:00
|
|
|
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;
|
|
|
|
}
|