mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 02:17:12 +00:00
Merge pull request #6755 from xThaid/dplane_batching
zebra: dataplane batching
This commit is contained in:
commit
659d56e13f
@ -382,3 +382,73 @@ Zebra Protocol Commands
|
||||
+------------------------------------+-------+
|
||||
| ZEBRA_OPAQUE_UNREGISTER | 109 |
|
||||
+------------------------------------+-------+
|
||||
|
||||
Dataplane batching
|
||||
=========================
|
||||
|
||||
Dataplane batching is an optimization feature that reduces the processing
|
||||
time involved in the user space to kernel space transition for every message we
|
||||
want to send.
|
||||
|
||||
Design
|
||||
-----------
|
||||
|
||||
With our dataplane abstraction, we create a queue of dataplane context objects
|
||||
for the messages we want to send to the kernel. In a separate pthread, we
|
||||
loop over this queue and send the context objects to the appropriate
|
||||
dataplane. A batching enhancement tightly integrates with the dataplane
|
||||
context objects so they are able to be batch sent to dataplanes that support
|
||||
it.
|
||||
|
||||
There is one main change in the dataplane code. It does not call
|
||||
kernel-dependent functions one-by-one, but instead it hands a list of work down
|
||||
to the kernel level for processing.
|
||||
|
||||
Netlink
|
||||
^^^^^^^
|
||||
|
||||
At the moment, this is the only dataplane that allows for batch sending
|
||||
messages to it.
|
||||
|
||||
When messages must be sent to the kernel, they are consecutively added
|
||||
to the batch represented by the `struct nl_batch`. Context objects are firstly
|
||||
encoded to their binary representation. All the encoding functions use the same
|
||||
interface: take a context object, a buffer and a size of the buffer as an
|
||||
argument. It is important that they should handle a situation in which a message
|
||||
wouldn't fit in the buffer and return a proper error. To achieve a zero-copy
|
||||
(in the user space only) messages are encoded to the same buffer which will
|
||||
be passed to the kernel. Hence, we can theoretically hit the boundary of the
|
||||
buffer.
|
||||
|
||||
Messages stored in the batch are sent if one of the conditions occurs:
|
||||
|
||||
- When an encoding function returns the buffer overflow error. The context
|
||||
object that caused this error is re-added to the new, empty batch.
|
||||
|
||||
- When the size of the batch hits certain limit.
|
||||
|
||||
- When the namespace of a currently being processed context object is
|
||||
different from all the previous ones. They have to be sent through
|
||||
distinct sockets, so the messages cannot share the same buffer.
|
||||
|
||||
- After the last message from the list is processed.
|
||||
|
||||
As mentioned earlier, there is a special threshold which is smaller than
|
||||
the size of the underlying buffer. It prevents the overflow error and thus
|
||||
eliminates the case, in which a message is encoded twice.
|
||||
|
||||
The buffer used in the batching is global, since allocating that big amount of
|
||||
memory every time wouldn't be most effective. However, its size can be changed
|
||||
dynamically, using hidden vtysh command:
|
||||
``zebra kernel netlink batch-tx-buf (1-1048576) (1-1048576)``. This feature is
|
||||
only used in tests and shouldn't be utilized in any other place.
|
||||
|
||||
For every failed message in the batch, the kernel responds with an error
|
||||
message. Error messages are kept in the same order as they were sent, so parsing the
|
||||
response is straightforward. We use the two pointer technique to match
|
||||
requests with responses and then set appropriate status of dataplane context
|
||||
objects. There is also a global receive buffer and it is assumed that whatever
|
||||
the kernel sends it will fit in this buffer. The payload of netlink error messages
|
||||
consists of a error code and the original netlink message of the request, so
|
||||
the batch response won't be bigger than the batch request increased by
|
||||
some space for the headers.
|
||||
|
0
tests/topotests/zebra_netlink/__init__.py
Normal file
0
tests/topotests/zebra_netlink/__init__.py
Normal file
0
tests/topotests/zebra_netlink/r1/sharpd.conf
Normal file
0
tests/topotests/zebra_netlink/r1/sharpd.conf
Normal file
2802
tests/topotests/zebra_netlink/r1/v4_route.json
Normal file
2802
tests/topotests/zebra_netlink/r1/v4_route.json
Normal file
File diff suppressed because it is too large
Load Diff
2
tests/topotests/zebra_netlink/r1/zebra.conf
Normal file
2
tests/topotests/zebra_netlink/r1/zebra.conf
Normal file
@ -0,0 +1,2 @@
|
||||
int r1-eth0
|
||||
ip address 192.168.1.1/24
|
131
tests/topotests/zebra_netlink/test_zebra_netlink.py
Executable file
131
tests/topotests/zebra_netlink/test_zebra_netlink.py
Executable file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# test_zebra_netlink.py
|
||||
#
|
||||
# Copyright (c) 2020 by
|
||||
#
|
||||
# Permission to use, copy, modify, and/or 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 NETDEF DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
|
||||
#
|
||||
|
||||
"""
|
||||
test_zebra_netlink.py: Test some basic interactions with kernel using Netlink
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import pytest
|
||||
import json
|
||||
import platform
|
||||
from functools import partial
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
from lib.common_config import shutdown_bringup_interface
|
||||
|
||||
# Required to instantiate the topology builder class.
|
||||
from mininet.topo import Topo
|
||||
|
||||
#####################################################
|
||||
##
|
||||
## Network Topology Definition
|
||||
##
|
||||
#####################################################
|
||||
|
||||
|
||||
class ZebraTopo(Topo):
|
||||
"Test topology builder"
|
||||
|
||||
def build(self, *_args, **_opts):
|
||||
"Build function"
|
||||
tgen = get_topogen(self)
|
||||
|
||||
tgen.add_router("r1")
|
||||
|
||||
# Create a empty network for router 1
|
||||
switch = tgen.add_switch("s1")
|
||||
switch.add_link(tgen.gears["r1"])
|
||||
|
||||
|
||||
#####################################################
|
||||
##
|
||||
## Tests starting
|
||||
##
|
||||
#####################################################
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"Sets up the pytest environment"
|
||||
tgen = Topogen(ZebraTopo, mod.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
router_list = tgen.routers()
|
||||
for rname, router in router_list.iteritems():
|
||||
router.load_config(
|
||||
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
|
||||
)
|
||||
|
||||
router.load_config(
|
||||
TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
|
||||
)
|
||||
|
||||
# Initialize all routers.
|
||||
tgen.start_router()
|
||||
|
||||
|
||||
def teardown_module(_mod):
|
||||
"Teardown the pytest environment"
|
||||
tgen = get_topogen()
|
||||
|
||||
# This function tears down the whole topology.
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def test_zebra_netlink_batching():
|
||||
"Test the situation where dataplane fills netlink send buffer entirely."
|
||||
logger.info(
|
||||
"Test the situation where dataplane fills netlink send buffer entirely."
|
||||
)
|
||||
tgen = get_topogen()
|
||||
if tgen.routers_have_failure():
|
||||
ptyest.skip("skipped because of preview test failure")
|
||||
r1 = tgen.gears["r1"]
|
||||
|
||||
# Reduce the size of the buffer to hit the limit.
|
||||
r1.vtysh_cmd("conf t\nzebra kernel netlink batch-tx-buf 256 256")
|
||||
|
||||
r1.vtysh_cmd("sharp install routes 2.1.3.7 nexthop 192.168.1.1 100")
|
||||
json_file = "{}/r1/v4_route.json".format(CWD)
|
||||
expected = json.loads(open(json_file).read())
|
||||
test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expected,)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
|
||||
assertmsg = '"r1" JSON output mismatches'
|
||||
assert result is None, assertmsg
|
||||
|
||||
r1.vtysh_cmd("sharp remove routes 2.1.3.7 100")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
@ -987,7 +987,8 @@ int kernel_interface_set_master(struct interface *master,
|
||||
}
|
||||
|
||||
/* Interface address modification. */
|
||||
static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx)
|
||||
static ssize_t netlink_address_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
int bytelen;
|
||||
const struct prefix *p;
|
||||
@ -997,64 +998,72 @@ static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx)
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifaddrmsg ifa;
|
||||
char buf[NL_PKT_BUF_SIZE];
|
||||
} req;
|
||||
char buf[0];
|
||||
} *req = buf;
|
||||
|
||||
if (buflen < sizeof(*req))
|
||||
return 0;
|
||||
|
||||
p = dplane_ctx_get_intf_addr(ctx);
|
||||
memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
|
||||
memset(req, 0, sizeof(*req));
|
||||
|
||||
bytelen = (p->family == AF_INET ? 4 : 16);
|
||||
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST;
|
||||
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
req->n.nlmsg_flags = NLM_F_REQUEST;
|
||||
|
||||
if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL)
|
||||
cmd = RTM_NEWADDR;
|
||||
else
|
||||
cmd = RTM_DELADDR;
|
||||
|
||||
req.n.nlmsg_type = cmd;
|
||||
req.ifa.ifa_family = p->family;
|
||||
req->n.nlmsg_type = cmd;
|
||||
req->ifa.ifa_family = p->family;
|
||||
|
||||
req.ifa.ifa_index = dplane_ctx_get_ifindex(ctx);
|
||||
req->ifa.ifa_index = dplane_ctx_get_ifindex(ctx);
|
||||
|
||||
nl_attr_put(&req.n, sizeof(req), IFA_LOCAL, &p->u.prefix, bytelen);
|
||||
if (!nl_attr_put(&req->n, buflen, IFA_LOCAL, &p->u.prefix, bytelen))
|
||||
return 0;
|
||||
|
||||
if (p->family == AF_INET) {
|
||||
if (dplane_ctx_intf_is_connected(ctx)) {
|
||||
p = dplane_ctx_get_intf_dest(ctx);
|
||||
nl_attr_put(&req.n, sizeof(req), IFA_ADDRESS,
|
||||
&p->u.prefix, bytelen);
|
||||
if (!nl_attr_put(&req->n, buflen, IFA_ADDRESS,
|
||||
&p->u.prefix, bytelen))
|
||||
return 0;
|
||||
} else if (cmd == RTM_NEWADDR) {
|
||||
struct in_addr broad = {
|
||||
.s_addr = ipv4_broadcast_addr(p->u.prefix4.s_addr,
|
||||
p->prefixlen)
|
||||
};
|
||||
nl_attr_put(&req.n, sizeof(req), IFA_BROADCAST, &broad,
|
||||
bytelen);
|
||||
if (!nl_attr_put(&req->n, buflen, IFA_BROADCAST, &broad,
|
||||
bytelen))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* p is now either address or destination/bcast addr */
|
||||
req.ifa.ifa_prefixlen = p->prefixlen;
|
||||
req->ifa.ifa_prefixlen = p->prefixlen;
|
||||
|
||||
if (dplane_ctx_intf_is_secondary(ctx))
|
||||
SET_FLAG(req.ifa.ifa_flags, IFA_F_SECONDARY);
|
||||
SET_FLAG(req->ifa.ifa_flags, IFA_F_SECONDARY);
|
||||
|
||||
if (dplane_ctx_intf_has_label(ctx)) {
|
||||
label = dplane_ctx_get_intf_label(ctx);
|
||||
nl_attr_put(&req.n, sizeof(req), IFA_LABEL, label,
|
||||
strlen(label) + 1);
|
||||
if (!nl_attr_put(&req->n, buflen, IFA_LABEL, label,
|
||||
strlen(label) + 1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return netlink_talk_info(netlink_talk_filter, &req.n,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
return NLMSG_ALIGN(req->n.nlmsg_len);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result kernel_address_update_ctx(struct zebra_dplane_ctx *ctx)
|
||||
enum netlink_msg_status
|
||||
netlink_put_address_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
return (netlink_address_ctx(ctx) == 0 ?
|
||||
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
return netlink_batch_add_msg(bth, ctx, netlink_address_msg_encoder,
|
||||
false);
|
||||
}
|
||||
|
||||
int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
|
@ -32,6 +32,10 @@ extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id,
|
||||
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
||||
extern int interface_lookup_netlink(struct zebra_ns *zns);
|
||||
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_address_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Set protodown status of interface.
|
||||
*
|
||||
|
@ -84,6 +84,27 @@
|
||||
#define RTPROT_MROUTED 17
|
||||
#endif
|
||||
|
||||
#define NL_DEFAULT_BATCH_BUFSIZE (16 * NL_PKT_BUF_SIZE)
|
||||
|
||||
/*
|
||||
* We limit the batch's size to a number smaller than the length of the
|
||||
* underlying buffer since the last message that wouldn't fit the batch would go
|
||||
* over the upper boundary and then it would have to be encoded again into a new
|
||||
* buffer. If the difference between the limit and the length of the buffer is
|
||||
* big enough (bigger than the biggest Netlink message) then this situation
|
||||
* won't occur.
|
||||
*/
|
||||
#define NL_DEFAULT_BATCH_SEND_THRESHOLD (15 * NL_PKT_BUF_SIZE)
|
||||
|
||||
/*
|
||||
* For every request sent to the kernel that has failed we get an error message,
|
||||
* which contains a standard netlink message header and the payload consisting
|
||||
* of an error code and the original netlink mesage. So the receiving buffer
|
||||
* must be at least as big as the transmitting buffer increased by some space
|
||||
* for headers.
|
||||
*/
|
||||
#define NL_BATCH_RX_BUFSIZE (NL_DEFAULT_BATCH_BUFSIZE + NL_PKT_BUF_SIZE)
|
||||
|
||||
static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
|
||||
{RTM_DELROUTE, "RTM_DELROUTE"},
|
||||
{RTM_GETROUTE, "RTM_GETROUTE"},
|
||||
@ -151,6 +172,62 @@ extern uint32_t nl_rcvbufsize;
|
||||
|
||||
extern struct zebra_privs_t zserv_privs;
|
||||
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers")
|
||||
|
||||
size_t nl_batch_tx_bufsize;
|
||||
char *nl_batch_tx_buf;
|
||||
|
||||
char nl_batch_rx_buf[NL_BATCH_RX_BUFSIZE];
|
||||
|
||||
_Atomic uint32_t nl_batch_bufsize = NL_DEFAULT_BATCH_BUFSIZE;
|
||||
_Atomic uint32_t nl_batch_send_threshold = NL_DEFAULT_BATCH_SEND_THRESHOLD;
|
||||
|
||||
struct nl_batch {
|
||||
void *buf;
|
||||
size_t bufsiz;
|
||||
size_t limit;
|
||||
|
||||
void *buf_head;
|
||||
size_t curlen;
|
||||
size_t msgcnt;
|
||||
|
||||
const struct zebra_dplane_info *zns;
|
||||
|
||||
struct dplane_ctx_q ctx_list;
|
||||
|
||||
/*
|
||||
* Pointer to the queue of completed contexts outbound back
|
||||
* towards the dataplane module.
|
||||
*/
|
||||
struct dplane_ctx_q *ctx_out_q;
|
||||
};
|
||||
|
||||
int netlink_config_write_helper(struct vty *vty)
|
||||
{
|
||||
uint32_t size =
|
||||
atomic_load_explicit(&nl_batch_bufsize, memory_order_relaxed);
|
||||
uint32_t threshold = atomic_load_explicit(&nl_batch_send_threshold,
|
||||
memory_order_relaxed);
|
||||
|
||||
if (size != NL_DEFAULT_BATCH_BUFSIZE
|
||||
|| threshold != NL_DEFAULT_BATCH_SEND_THRESHOLD)
|
||||
vty_out(vty, "zebra kernel netlink batch-tx-buf %u %u\n", size,
|
||||
threshold);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netlink_set_batch_buffer_size(uint32_t size, uint32_t threshold, bool set)
|
||||
{
|
||||
if (!set) {
|
||||
size = NL_DEFAULT_BATCH_BUFSIZE;
|
||||
threshold = NL_DEFAULT_BATCH_SEND_THRESHOLD;
|
||||
}
|
||||
|
||||
atomic_store_explicit(&nl_batch_bufsize, size, memory_order_relaxed);
|
||||
atomic_store_explicit(&nl_batch_send_threshold, threshold,
|
||||
memory_order_relaxed);
|
||||
}
|
||||
|
||||
int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
{
|
||||
@ -1008,9 +1085,10 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
|
||||
* startup -> Are we reading in under startup conditions
|
||||
* This is passed through eventually to filter.
|
||||
*/
|
||||
int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
|
||||
struct nlmsghdr *n,
|
||||
const struct zebra_dplane_info *dp_info, int startup)
|
||||
static int
|
||||
netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
|
||||
struct nlmsghdr *n, const struct zebra_dplane_info *dp_info,
|
||||
int startup)
|
||||
{
|
||||
const struct nlsock *nl;
|
||||
|
||||
@ -1080,6 +1158,327 @@ int netlink_request(struct nlsock *nl, void *req)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl_batch_read_resp(struct nl_batch *bth)
|
||||
{
|
||||
struct nlmsghdr *h;
|
||||
struct sockaddr_nl snl;
|
||||
struct msghdr msg;
|
||||
int status, seq;
|
||||
const struct nlsock *nl;
|
||||
struct zebra_dplane_ctx *ctx;
|
||||
bool ignore_msg;
|
||||
|
||||
nl = &(bth->zns->nls);
|
||||
|
||||
msg.msg_name = (void *)&snl;
|
||||
msg.msg_namelen = sizeof(snl);
|
||||
|
||||
status = netlink_recv_msg(nl, msg, nl_batch_rx_buf,
|
||||
sizeof(nl_batch_rx_buf));
|
||||
if (status == -1 || status == 0)
|
||||
return status;
|
||||
|
||||
for (h = (struct nlmsghdr *)nl_batch_rx_buf;
|
||||
(status >= 0 && NLMSG_OK(h, (unsigned int)status));
|
||||
h = NLMSG_NEXT(h, status)) {
|
||||
ignore_msg = false;
|
||||
seq = h->nlmsg_seq;
|
||||
/*
|
||||
* Find the corresponding context object. Received responses are
|
||||
* in the same order as requests we sent, so we can simply
|
||||
* iterate over the context list and match responses with
|
||||
* requests at same time.
|
||||
*/
|
||||
while (true) {
|
||||
ctx = dplane_ctx_dequeue(&(bth->ctx_list));
|
||||
if (ctx == NULL)
|
||||
break;
|
||||
|
||||
dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx);
|
||||
|
||||
/* We have found corresponding context object. */
|
||||
if (dplane_ctx_get_ns(ctx)->nls.seq == seq)
|
||||
break;
|
||||
|
||||
/*
|
||||
* 'update' context objects take two consecutive
|
||||
* sequence numbers.
|
||||
*/
|
||||
if (dplane_ctx_is_update(ctx)
|
||||
&& dplane_ctx_get_ns(ctx)->nls.seq + 1 == seq) {
|
||||
/*
|
||||
* This is the situation where we get a response
|
||||
* to a message that should be ignored.
|
||||
*/
|
||||
ignore_msg = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore_msg)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We received a message with the sequence number that isn't
|
||||
* associated with any dplane context object.
|
||||
*/
|
||||
if (ctx == NULL) {
|
||||
zlog_debug(
|
||||
"%s: skipping unassociated response, seq number %d NS %u",
|
||||
__func__, h->nlmsg_seq, bth->zns->ns_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (h->nlmsg_type == NLMSG_ERROR) {
|
||||
int err = netlink_parse_error(nl, h, bth->zns, 0);
|
||||
|
||||
if (err == -1)
|
||||
dplane_ctx_set_status(
|
||||
ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
|
||||
zlog_debug("%s: netlink error message seq=%d ",
|
||||
__func__, h->nlmsg_seq);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here then we did not receive neither the ack nor
|
||||
* the error and instead received some other message in an
|
||||
* unexpected way.
|
||||
*/
|
||||
zlog_debug("%s: ignoring message type 0x%04x(%s) NS %u",
|
||||
__func__, h->nlmsg_type,
|
||||
nl_msg_type_to_str(h->nlmsg_type), bth->zns->ns_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nl_batch_reset(struct nl_batch *bth)
|
||||
{
|
||||
bth->buf_head = bth->buf;
|
||||
bth->curlen = 0;
|
||||
bth->msgcnt = 0;
|
||||
bth->zns = NULL;
|
||||
|
||||
TAILQ_INIT(&(bth->ctx_list));
|
||||
}
|
||||
|
||||
static void nl_batch_init(struct nl_batch *bth, struct dplane_ctx_q *ctx_out_q)
|
||||
{
|
||||
/*
|
||||
* If the size of the buffer has changed, free and then allocate a new
|
||||
* one.
|
||||
*/
|
||||
size_t bufsize =
|
||||
atomic_load_explicit(&nl_batch_bufsize, memory_order_relaxed);
|
||||
if (bufsize != nl_batch_tx_bufsize) {
|
||||
if (nl_batch_tx_buf)
|
||||
XFREE(MTYPE_NL_BUF, nl_batch_tx_buf);
|
||||
|
||||
nl_batch_tx_buf = XCALLOC(MTYPE_NL_BUF, bufsize);
|
||||
nl_batch_tx_bufsize = bufsize;
|
||||
}
|
||||
|
||||
bth->buf = nl_batch_tx_buf;
|
||||
bth->bufsiz = bufsize;
|
||||
bth->limit = atomic_load_explicit(&nl_batch_send_threshold,
|
||||
memory_order_relaxed);
|
||||
|
||||
bth->ctx_out_q = ctx_out_q;
|
||||
|
||||
nl_batch_reset(bth);
|
||||
}
|
||||
|
||||
static void nl_batch_send(struct nl_batch *bth)
|
||||
{
|
||||
struct zebra_dplane_ctx *ctx;
|
||||
bool err = false;
|
||||
|
||||
if (bth->curlen != 0 && bth->zns != NULL) {
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug("%s: %s, batch size=%zu, msg cnt=%zu",
|
||||
__func__, bth->zns->nls.name, bth->curlen,
|
||||
bth->msgcnt);
|
||||
|
||||
if (netlink_send_msg(&(bth->zns->nls), bth->buf, bth->curlen)
|
||||
== -1)
|
||||
err = true;
|
||||
|
||||
if (!err) {
|
||||
if (nl_batch_read_resp(bth) == -1)
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move remaining contexts to the outbound queue. */
|
||||
while (true) {
|
||||
ctx = dplane_ctx_dequeue(&(bth->ctx_list));
|
||||
if (ctx == NULL)
|
||||
break;
|
||||
|
||||
if (err)
|
||||
dplane_ctx_set_status(ctx,
|
||||
ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
|
||||
dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx);
|
||||
}
|
||||
|
||||
nl_batch_reset(bth);
|
||||
}
|
||||
|
||||
enum netlink_msg_status netlink_batch_add_msg(
|
||||
struct nl_batch *bth, struct zebra_dplane_ctx *ctx,
|
||||
ssize_t (*msg_encoder)(struct zebra_dplane_ctx *, void *, size_t),
|
||||
bool ignore_res)
|
||||
{
|
||||
int seq;
|
||||
ssize_t size;
|
||||
struct nlmsghdr *msgh;
|
||||
|
||||
size = (*msg_encoder)(ctx, bth->buf_head, bth->bufsiz - bth->curlen);
|
||||
|
||||
/*
|
||||
* If there was an error while encoding the message (other than buffer
|
||||
* overflow) then return an error.
|
||||
*/
|
||||
if (size < 0)
|
||||
return FRR_NETLINK_ERROR;
|
||||
|
||||
/*
|
||||
* If the message doesn't fit entirely in the buffer then send the batch
|
||||
* and retry.
|
||||
*/
|
||||
if (size == 0) {
|
||||
nl_batch_send(bth);
|
||||
size = (*msg_encoder)(ctx, bth->buf_head,
|
||||
bth->bufsiz - bth->curlen);
|
||||
/*
|
||||
* If the message doesn't fit in the empty buffer then just
|
||||
* return an error.
|
||||
*/
|
||||
if (size <= 0)
|
||||
return FRR_NETLINK_ERROR;
|
||||
}
|
||||
|
||||
seq = dplane_ctx_get_ns(ctx)->nls.seq;
|
||||
if (ignore_res)
|
||||
seq++;
|
||||
|
||||
msgh = (struct nlmsghdr *)bth->buf_head;
|
||||
msgh->nlmsg_seq = seq;
|
||||
msgh->nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
|
||||
|
||||
bth->zns = dplane_ctx_get_ns(ctx);
|
||||
bth->buf_head = ((char *)bth->buf_head) + size;
|
||||
bth->curlen += size;
|
||||
bth->msgcnt++;
|
||||
|
||||
return FRR_NETLINK_QUEUED;
|
||||
}
|
||||
|
||||
static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
if (dplane_ctx_is_skip_kernel(ctx))
|
||||
return FRR_NETLINK_SUCCESS;
|
||||
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
|
||||
case DPLANE_OP_ROUTE_INSTALL:
|
||||
case DPLANE_OP_ROUTE_UPDATE:
|
||||
case DPLANE_OP_ROUTE_DELETE:
|
||||
return netlink_put_route_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
case DPLANE_OP_NH_UPDATE:
|
||||
case DPLANE_OP_NH_DELETE:
|
||||
return netlink_put_nexthop_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_LSP_INSTALL:
|
||||
case DPLANE_OP_LSP_UPDATE:
|
||||
case DPLANE_OP_LSP_DELETE:
|
||||
return netlink_put_lsp_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_PW_INSTALL:
|
||||
case DPLANE_OP_PW_UNINSTALL:
|
||||
return netlink_put_pw_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
return netlink_put_address_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_MAC_INSTALL:
|
||||
case DPLANE_OP_MAC_DELETE:
|
||||
return netlink_put_mac_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
return netlink_put_neigh_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_RULE_ADD:
|
||||
case DPLANE_OP_RULE_DELETE:
|
||||
case DPLANE_OP_RULE_UPDATE:
|
||||
return netlink_put_rule_update_msg(bth, ctx);
|
||||
|
||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
case DPLANE_OP_ROUTE_NOTIFY:
|
||||
case DPLANE_OP_LSP_NOTIFY:
|
||||
return FRR_NETLINK_SUCCESS;
|
||||
|
||||
case DPLANE_OP_NONE:
|
||||
return FRR_NETLINK_ERROR;
|
||||
}
|
||||
|
||||
return FRR_NETLINK_ERROR;
|
||||
}
|
||||
|
||||
void kernel_update_multi(struct dplane_ctx_q *ctx_list)
|
||||
{
|
||||
struct nl_batch batch;
|
||||
struct zebra_dplane_ctx *ctx;
|
||||
struct dplane_ctx_q handled_list;
|
||||
enum netlink_msg_status res;
|
||||
|
||||
TAILQ_INIT(&handled_list);
|
||||
nl_batch_init(&batch, &handled_list);
|
||||
|
||||
while (true) {
|
||||
ctx = dplane_ctx_dequeue(ctx_list);
|
||||
if (ctx == NULL)
|
||||
break;
|
||||
|
||||
if (batch.zns != NULL
|
||||
&& batch.zns->ns_id != dplane_ctx_get_ns(ctx)->ns_id)
|
||||
nl_batch_send(&batch);
|
||||
|
||||
/*
|
||||
* Assume all messages will succeed and then mark only the ones
|
||||
* that failed.
|
||||
*/
|
||||
dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
|
||||
|
||||
res = nl_put_msg(&batch, ctx);
|
||||
|
||||
dplane_ctx_enqueue_tail(&(batch.ctx_list), ctx);
|
||||
if (res == FRR_NETLINK_ERROR)
|
||||
dplane_ctx_set_status(ctx,
|
||||
ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
|
||||
if (batch.curlen > batch.limit)
|
||||
nl_batch_send(&batch);
|
||||
}
|
||||
|
||||
nl_batch_send(&batch);
|
||||
|
||||
TAILQ_INIT(ctx_list);
|
||||
dplane_ctx_list_append(ctx_list, &handled_list);
|
||||
}
|
||||
|
||||
/* Exported interface function. This function simply calls
|
||||
netlink_socket (). */
|
||||
void kernel_init(struct zebra_ns *zns)
|
||||
|
@ -98,13 +98,49 @@ extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup);
|
||||
extern int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
|
||||
struct nlmsghdr *n, struct nlsock *nl,
|
||||
struct zebra_ns *zns, int startup);
|
||||
/* Version with 'info' struct only */
|
||||
int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
|
||||
struct nlmsghdr *n,
|
||||
const struct zebra_dplane_info *dp_info, int startup);
|
||||
|
||||
extern int netlink_request(struct nlsock *nl, void *req);
|
||||
|
||||
enum netlink_msg_status {
|
||||
FRR_NETLINK_SUCCESS,
|
||||
FRR_NETLINK_ERROR,
|
||||
FRR_NETLINK_QUEUED,
|
||||
};
|
||||
|
||||
struct nl_batch;
|
||||
|
||||
/*
|
||||
* netlink_batch_add_msg - add message to the netlink batch using dplane
|
||||
* context object.
|
||||
*
|
||||
* @ctx: Dataplane context
|
||||
* @msg_encoder: A function that encodes dplane context object into
|
||||
* netlink message. Should take dplane context object,
|
||||
* pointer to a buffer and buffer's length as parameters
|
||||
* and should return -1 on error, 0 on buffer overflow or
|
||||
* size of the encoded message.
|
||||
* @ignore_res: Whether the result of this message should be ignored.
|
||||
* This should be used in some 'update' cases where we
|
||||
* need to send two messages for one context object.
|
||||
*
|
||||
* Return: Status of the message.
|
||||
*/
|
||||
extern enum netlink_msg_status netlink_batch_add_msg(
|
||||
struct nl_batch *bth, struct zebra_dplane_ctx *ctx,
|
||||
ssize_t (*msg_encoder)(struct zebra_dplane_ctx *, void *, size_t),
|
||||
bool ignore_res);
|
||||
|
||||
/*
|
||||
* Vty/cli apis
|
||||
*/
|
||||
extern int netlink_config_write_helper(struct vty *vty);
|
||||
|
||||
/*
|
||||
* Configure size of the batch buffer and sending threshold. If 'unset', reset
|
||||
* to default value.
|
||||
*/
|
||||
extern void netlink_set_batch_buffer_size(uint32_t size, uint32_t threshold,
|
||||
bool set);
|
||||
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1464,4 +1464,98 @@ void kernel_terminate(struct zebra_ns *zns, bool complete)
|
||||
return;
|
||||
}
|
||||
|
||||
void kernel_update_multi(struct dplane_ctx_q *ctx_list)
|
||||
{
|
||||
struct zebra_dplane_ctx *ctx;
|
||||
struct dplane_ctx_q handled_list;
|
||||
enum zebra_dplane_result res;
|
||||
|
||||
TAILQ_INIT(&handled_list);
|
||||
|
||||
while (true) {
|
||||
ctx = dplane_ctx_dequeue(ctx_list);
|
||||
if (ctx == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* A previous provider plugin may have asked to skip the
|
||||
* kernel update.
|
||||
*/
|
||||
if (dplane_ctx_is_skip_kernel(ctx)) {
|
||||
res = ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
goto skip_one;
|
||||
}
|
||||
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
|
||||
case DPLANE_OP_ROUTE_INSTALL:
|
||||
case DPLANE_OP_ROUTE_UPDATE:
|
||||
case DPLANE_OP_ROUTE_DELETE:
|
||||
res = kernel_route_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
case DPLANE_OP_NH_UPDATE:
|
||||
case DPLANE_OP_NH_DELETE:
|
||||
res = kernel_nexthop_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_LSP_INSTALL:
|
||||
case DPLANE_OP_LSP_UPDATE:
|
||||
case DPLANE_OP_LSP_DELETE:
|
||||
res = kernel_lsp_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_PW_INSTALL:
|
||||
case DPLANE_OP_PW_UNINSTALL:
|
||||
res = kernel_pw_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
res = kernel_address_update_ctx(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_MAC_INSTALL:
|
||||
case DPLANE_OP_MAC_DELETE:
|
||||
res = kernel_mac_update_ctx(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
res = kernel_neigh_update_ctx(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_RULE_ADD:
|
||||
case DPLANE_OP_RULE_DELETE:
|
||||
case DPLANE_OP_RULE_UPDATE:
|
||||
res = kernel_pbr_rule_update(ctx);
|
||||
break;
|
||||
|
||||
/* Ignore 'notifications' - no-op */
|
||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
case DPLANE_OP_ROUTE_NOTIFY:
|
||||
case DPLANE_OP_LSP_NOTIFY:
|
||||
res = ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
res = ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
skip_one:
|
||||
dplane_ctx_set_status(ctx, res);
|
||||
|
||||
dplane_ctx_enqueue_tail(&handled_list, ctx);
|
||||
}
|
||||
|
||||
TAILQ_INIT(ctx_list);
|
||||
dplane_ctx_list_append(ctx_list, &handled_list);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_NETLINK */
|
||||
|
12
zebra/rt.h
12
zebra/rt.h
@ -40,7 +40,7 @@ extern "C" {
|
||||
#define RSYSTEM_ROUTE(type) \
|
||||
((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT)
|
||||
|
||||
|
||||
#ifndef HAVE_NETLINK
|
||||
/*
|
||||
* Update or delete a route, nexthop, LSP, pseudowire, or vxlan MAC from the
|
||||
* kernel, using info from a dataplane context.
|
||||
@ -63,6 +63,11 @@ enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx);
|
||||
|
||||
enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx);
|
||||
|
||||
extern enum zebra_dplane_result
|
||||
kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx);
|
||||
|
||||
#endif /* !HAVE_NETLINK */
|
||||
|
||||
extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
|
||||
int llalen, ns_id_t ns_id);
|
||||
extern int kernel_interface_set_master(struct interface *master,
|
||||
@ -97,6 +102,11 @@ extern int kernel_upd_mac_nhg(uint32_t nhg_id, uint32_t nh_cnt,
|
||||
struct nh_grp *nh_ids);
|
||||
extern int kernel_del_mac_nhg(uint32_t nhg_id);
|
||||
|
||||
/*
|
||||
* Message batching interface.
|
||||
*/
|
||||
extern void kernel_update_multi(struct dplane_ctx_q *ctx_list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -2230,19 +2230,11 @@ nexthop_done:
|
||||
return NLMSG_ALIGN(req->n.nlmsg_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* kernel_nexthop_update() - Update/delete a nexthop from the kernel
|
||||
*
|
||||
* @ctx: Dataplane context
|
||||
*
|
||||
* Return: Dataplane result flag
|
||||
*/
|
||||
enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
|
||||
static ssize_t netlink_nexthop_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
enum dplane_op_e op;
|
||||
int cmd = 0;
|
||||
int ret = 0;
|
||||
char buf[NL_PKT_BUF_SIZE];
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
|
||||
@ -2253,33 +2245,43 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
|
||||
flog_err(EC_ZEBRA_NHG_FIB_UPDATE,
|
||||
"Context received for kernel nexthop update with incorrect OP code (%u)",
|
||||
op);
|
||||
return ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Nothing to do if the kernel doesn't support nexthop objects */
|
||||
if (!kernel_nexthops_supported())
|
||||
return ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
|
||||
if (netlink_nexthop_msg_encode(cmd, ctx, buf, sizeof(buf)) > 0)
|
||||
ret = netlink_talk_info(netlink_talk_filter, (void *)&buf,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS
|
||||
: ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
return netlink_nexthop_msg_encode(cmd, ctx, buf, buflen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update or delete a prefix from the kernel,
|
||||
* using info from a dataplane context.
|
||||
*/
|
||||
enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
|
||||
enum netlink_msg_status
|
||||
netlink_put_nexthop_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
int cmd, ret;
|
||||
/* Nothing to do if the kernel doesn't support nexthop objects */
|
||||
if (!kernel_nexthops_supported())
|
||||
return FRR_NETLINK_SUCCESS;
|
||||
|
||||
return netlink_batch_add_msg(bth, ctx, netlink_nexthop_msg_encoder,
|
||||
false);
|
||||
}
|
||||
|
||||
static ssize_t netlink_newroute_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
return netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, buf,
|
||||
buflen, false, false);
|
||||
}
|
||||
|
||||
static ssize_t netlink_delroute_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
return netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, buf,
|
||||
buflen, false, false);
|
||||
}
|
||||
|
||||
enum netlink_msg_status
|
||||
netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
int cmd;
|
||||
const struct prefix *p = dplane_ctx_get_dest(ctx);
|
||||
struct nexthop *nexthop;
|
||||
uint8_t nl_pkt[NL_PKT_BUF_SIZE];
|
||||
|
||||
if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
|
||||
cmd = RTM_DELROUTE;
|
||||
@ -2289,7 +2291,6 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
|
||||
|
||||
if (p->family == AF_INET || v6_rr_semantics) {
|
||||
/* Single 'replace' operation */
|
||||
cmd = RTM_NEWROUTE;
|
||||
|
||||
/*
|
||||
* With route replace semantics in place
|
||||
@ -2299,17 +2300,11 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
|
||||
* route should cause us to withdraw from
|
||||
* the kernel the old non-system route
|
||||
*/
|
||||
if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) &&
|
||||
!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
|
||||
if (netlink_route_multipath_msg_encode(
|
||||
RTM_DELROUTE, ctx, nl_pkt,
|
||||
sizeof(nl_pkt), false, false)
|
||||
> 0)
|
||||
netlink_talk_info(
|
||||
netlink_talk_filter,
|
||||
(struct nlmsghdr *)nl_pkt,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
}
|
||||
if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))
|
||||
&& !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
|
||||
netlink_batch_add_msg(
|
||||
bth, ctx, netlink_delroute_msg_encoder,
|
||||
true);
|
||||
} else {
|
||||
/*
|
||||
* So v6 route replace semantics are not in
|
||||
@ -2323,51 +2318,24 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
|
||||
* of the route delete. If that happens yeah we're
|
||||
* screwed.
|
||||
*/
|
||||
if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
|
||||
if (netlink_route_multipath_msg_encode(
|
||||
RTM_DELROUTE, ctx, nl_pkt,
|
||||
sizeof(nl_pkt), false, false)
|
||||
> 0)
|
||||
netlink_talk_info(
|
||||
netlink_talk_filter,
|
||||
(struct nlmsghdr *)nl_pkt,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
}
|
||||
cmd = RTM_NEWROUTE;
|
||||
if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
|
||||
netlink_batch_add_msg(
|
||||
bth, ctx, netlink_delroute_msg_encoder,
|
||||
true);
|
||||
}
|
||||
|
||||
} else {
|
||||
return ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
}
|
||||
|
||||
if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) {
|
||||
if (netlink_route_multipath_msg_encode(
|
||||
cmd, ctx, nl_pkt, sizeof(nl_pkt), false, false)
|
||||
> 0)
|
||||
ret = netlink_talk_info(netlink_talk_filter,
|
||||
(struct nlmsghdr *)nl_pkt,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
else
|
||||
ret = -1;
|
||||
|
||||
cmd = RTM_NEWROUTE;
|
||||
} else
|
||||
ret = 0;
|
||||
if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
|
||||
/* Update installed nexthops to signal which have been
|
||||
* installed.
|
||||
*/
|
||||
for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
return FRR_NETLINK_ERROR;
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)))
|
||||
return FRR_NETLINK_SUCCESS;
|
||||
|
||||
return (ret == 0 ?
|
||||
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
return netlink_batch_add_msg(bth, ctx,
|
||||
cmd == RTM_NEWROUTE
|
||||
? netlink_newroute_msg_encoder
|
||||
: netlink_delroute_msg_encoder,
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2783,23 +2751,16 @@ static ssize_t netlink_neigh_update_msg_encode(
|
||||
* Add remote VTEP to the flood list for this VxLAN interface (VNI). This
|
||||
* is done by adding an FDB entry with a MAC of 00:00:00:00:00:00.
|
||||
*/
|
||||
static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
|
||||
int cmd)
|
||||
static ssize_t
|
||||
netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
struct ethaddr dst_mac = {.octet = {0}};
|
||||
uint8_t nl_pkt[NL_PKT_BUF_SIZE];
|
||||
|
||||
if (netlink_neigh_update_msg_encode(
|
||||
ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
|
||||
PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT),
|
||||
0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/,
|
||||
nl_pkt, sizeof(nl_pkt))
|
||||
<= 0)
|
||||
return -1;
|
||||
|
||||
return netlink_talk_info(netlink_talk_filter,
|
||||
(struct nlmsghdr *)nl_pkt,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
return netlink_neigh_update_msg_encode(
|
||||
ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
|
||||
PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/,
|
||||
false /*nfy*/, 0 /*nfy_flags*/, buf, buflen);
|
||||
}
|
||||
|
||||
#ifndef NDA_RTA
|
||||
@ -3148,9 +3109,8 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
|
||||
/*
|
||||
* Netlink-specific handler for MAC updates using dataplane context object.
|
||||
*/
|
||||
ssize_t
|
||||
netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
|
||||
size_t datalen)
|
||||
ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
|
||||
size_t datalen)
|
||||
{
|
||||
struct ipaddr vtep_ip;
|
||||
vlanid_t vid;
|
||||
@ -3626,15 +3586,14 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
|
||||
/*
|
||||
* Utility neighbor-update function, using info from dplane context.
|
||||
*/
|
||||
static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
|
||||
int cmd)
|
||||
static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
|
||||
int cmd, void *buf, size_t buflen)
|
||||
{
|
||||
const struct ipaddr *ip;
|
||||
const struct ethaddr *mac;
|
||||
uint8_t flags;
|
||||
uint16_t state;
|
||||
uint8_t family;
|
||||
uint8_t nl_pkt[NL_PKT_BUF_SIZE];
|
||||
|
||||
ip = dplane_ctx_neigh_get_ipaddr(ctx);
|
||||
mac = dplane_ctx_neigh_get_mac(ctx);
|
||||
@ -3659,60 +3618,55 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
|
||||
flags, state);
|
||||
}
|
||||
|
||||
if (netlink_neigh_update_msg_encode(ctx, cmd, mac, ip, true, family,
|
||||
RTN_UNICAST, flags, state,
|
||||
0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/,
|
||||
nl_pkt, sizeof(nl_pkt))
|
||||
<= 0)
|
||||
return -1;
|
||||
return netlink_neigh_update_msg_encode(
|
||||
ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, state,
|
||||
0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, buf, buflen);
|
||||
}
|
||||
|
||||
return netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen);
|
||||
break;
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen);
|
||||
break;
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH, buf,
|
||||
buflen);
|
||||
break;
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf,
|
||||
buflen);
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update MAC, using dataplane context object.
|
||||
*/
|
||||
enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
|
||||
|
||||
enum netlink_msg_status netlink_put_mac_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
uint8_t nl_pkt[NL_PKT_BUF_SIZE];
|
||||
ssize_t rv;
|
||||
|
||||
rv = netlink_macfdb_update_ctx(ctx, nl_pkt, sizeof(nl_pkt));
|
||||
if (rv <= 0)
|
||||
return ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
|
||||
rv = netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
|
||||
return rv == 0 ?
|
||||
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
return netlink_batch_add_msg(bth, ctx, netlink_macfdb_update_ctx,
|
||||
false);
|
||||
}
|
||||
|
||||
enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
|
||||
enum netlink_msg_status
|
||||
netlink_put_neigh_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH);
|
||||
break;
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH);
|
||||
break;
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH);
|
||||
break;
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret == 0 ?
|
||||
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
return netlink_batch_add_msg(bth, ctx, netlink_neigh_msg_encoder,
|
||||
false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -74,7 +74,7 @@ extern ssize_t netlink_route_multipath_msg_encode(int cmd,
|
||||
uint8_t *data, size_t datalen,
|
||||
bool fpm, bool force_nhg);
|
||||
extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx,
|
||||
uint8_t *data, size_t datalen);
|
||||
void *data, size_t datalen);
|
||||
|
||||
extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
||||
extern int netlink_route_read(struct zebra_ns *zns);
|
||||
@ -101,6 +101,23 @@ extern int netlink_neigh_read_specific_ip(struct ipaddr *ip,
|
||||
struct interface *vlan_if);
|
||||
extern vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id);
|
||||
|
||||
struct nl_batch;
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_route_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx);
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_nexthop_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx);
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_mac_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_neigh_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx);
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_lsp_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_pw_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -358,20 +358,6 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
|
||||
}
|
||||
} /* Elevated privs */
|
||||
|
||||
if (RSYSTEM_ROUTE(type)
|
||||
&& dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE) {
|
||||
struct nexthop *nexthop;
|
||||
|
||||
for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,8 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx,
|
||||
char buf1[PREFIX_STRLEN];
|
||||
char buf2[PREFIX_STRLEN];
|
||||
|
||||
if (buflen < sizeof(*req))
|
||||
return 0;
|
||||
memset(req, 0, sizeof(*req));
|
||||
family = PREFIX_FAMILY(src_ip);
|
||||
bytelen = (family == AF_INET ? 4 : 16);
|
||||
@ -148,53 +150,55 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx,
|
||||
return NLMSG_ALIGN(req->n.nlmsg_len);
|
||||
}
|
||||
|
||||
/* Install or uninstall specified rule for a specific interface.
|
||||
* Form netlink message and ship it.
|
||||
*/
|
||||
static int netlink_rule_update_internal(
|
||||
int cmd, const struct zebra_dplane_ctx *ctx, uint32_t filter_bm,
|
||||
uint32_t priority, uint32_t table, const struct prefix *src_ip,
|
||||
const struct prefix *dst_ip, uint32_t fwmark, uint8_t dsfield)
|
||||
static ssize_t netlink_rule_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
char buf[NL_PKT_BUF_SIZE];
|
||||
int cmd = RTM_NEWRULE;
|
||||
|
||||
netlink_rule_msg_encode(cmd, ctx, filter_bm, priority, table, src_ip,
|
||||
dst_ip, fwmark, dsfield, buf, sizeof(buf));
|
||||
return netlink_talk_info(netlink_talk_filter, (void *)&buf,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
}
|
||||
/* Public functions */
|
||||
|
||||
/*
|
||||
* Add, update or delete a rule from the
|
||||
* kernel, using info from a dataplane context.
|
||||
*/
|
||||
enum zebra_dplane_result kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
enum dplane_op_e op;
|
||||
int cmd;
|
||||
int ret;
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
if (op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE)
|
||||
cmd = RTM_NEWRULE;
|
||||
else if (op == DPLANE_OP_RULE_DELETE)
|
||||
if (dplane_ctx_get_op(ctx) == DPLANE_OP_RULE_DELETE)
|
||||
cmd = RTM_DELRULE;
|
||||
else {
|
||||
flog_err(
|
||||
EC_ZEBRA_PBR_RULE_UPDATE,
|
||||
"Context received for kernel rule update with incorrect OP code (%u)",
|
||||
op);
|
||||
return ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
}
|
||||
|
||||
ret = netlink_rule_update_internal(
|
||||
return netlink_rule_msg_encode(
|
||||
cmd, ctx, dplane_ctx_rule_get_filter_bm(ctx),
|
||||
dplane_ctx_rule_get_priority(ctx),
|
||||
dplane_ctx_rule_get_table(ctx), dplane_ctx_rule_get_src_ip(ctx),
|
||||
dplane_ctx_rule_get_dst_ip(ctx),
|
||||
dplane_ctx_rule_get_fwmark(ctx),
|
||||
dplane_ctx_rule_get_dsfield(ctx));
|
||||
dplane_ctx_rule_get_dsfield(ctx), buf, buflen);
|
||||
}
|
||||
|
||||
static ssize_t netlink_oldrule_msg_encoder(struct zebra_dplane_ctx *ctx,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
return netlink_rule_msg_encode(
|
||||
RTM_DELRULE, ctx, dplane_ctx_rule_get_old_filter_bm(ctx),
|
||||
dplane_ctx_rule_get_old_priority(ctx),
|
||||
dplane_ctx_rule_get_old_table(ctx),
|
||||
dplane_ctx_rule_get_old_src_ip(ctx),
|
||||
dplane_ctx_rule_get_old_dst_ip(ctx),
|
||||
dplane_ctx_rule_get_old_fwmark(ctx),
|
||||
dplane_ctx_rule_get_old_dsfield(ctx), buf, buflen);
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
|
||||
enum netlink_msg_status
|
||||
netlink_put_rule_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
enum dplane_op_e op;
|
||||
enum netlink_msg_status ret;
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
if (!(op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE
|
||||
|| op == DPLANE_OP_RULE_DELETE)) {
|
||||
flog_err(
|
||||
EC_ZEBRA_PBR_RULE_UPDATE,
|
||||
"Context received for kernel rule update with incorrect OP code (%u)",
|
||||
op);
|
||||
return FRR_NETLINK_ERROR;
|
||||
}
|
||||
|
||||
ret = netlink_batch_add_msg(bth, ctx, netlink_rule_msg_encoder, false);
|
||||
|
||||
/**
|
||||
* Delete the old one.
|
||||
@ -202,19 +206,10 @@ enum zebra_dplane_result kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx)
|
||||
* Don't care about this result right?
|
||||
*/
|
||||
if (op == DPLANE_OP_RULE_UPDATE)
|
||||
netlink_rule_update_internal(
|
||||
RTM_DELRULE, ctx,
|
||||
dplane_ctx_rule_get_old_filter_bm(ctx),
|
||||
dplane_ctx_rule_get_old_priority(ctx),
|
||||
dplane_ctx_rule_get_old_table(ctx),
|
||||
dplane_ctx_rule_get_old_src_ip(ctx),
|
||||
dplane_ctx_rule_get_old_dst_ip(ctx),
|
||||
dplane_ctx_rule_get_old_fwmark(ctx),
|
||||
dplane_ctx_rule_get_old_dsfield(ctx));
|
||||
netlink_batch_add_msg(bth, ctx, netlink_oldrule_msg_encoder,
|
||||
true);
|
||||
|
||||
|
||||
return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS
|
||||
: ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -40,6 +40,9 @@ extern int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
||||
*/
|
||||
extern int netlink_rules_read(struct zebra_ns *zns);
|
||||
|
||||
extern enum netlink_msg_status
|
||||
netlink_put_rule_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -858,8 +858,6 @@ const char *dplane_res2str(enum zebra_dplane_result res)
|
||||
case ZEBRA_DPLANE_REQUEST_SUCCESS:
|
||||
ret = "SUCCESS";
|
||||
break;
|
||||
case ZEBRA_DPLANE_REQUEST_PENDING:
|
||||
ret = "PENDING";
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1979,6 +1977,7 @@ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
|
||||
* it probably won't require two messages
|
||||
*/
|
||||
dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE));
|
||||
ctx->zd_is_update = (op == DPLANE_OP_NH_UPDATE);
|
||||
|
||||
ret = AOK;
|
||||
|
||||
@ -2001,6 +2000,7 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
|
||||
/* Capture namespace info */
|
||||
dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
|
||||
(op == DPLANE_OP_LSP_UPDATE));
|
||||
ctx->zd_is_update = (op == DPLANE_OP_LSP_UPDATE);
|
||||
|
||||
memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp));
|
||||
|
||||
@ -2222,6 +2222,7 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
|
||||
|
||||
dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
|
||||
op == DPLANE_OP_RULE_UPDATE);
|
||||
ctx->zd_is_update = (op == DPLANE_OP_RULE_UPDATE);
|
||||
|
||||
ctx->zd_vrf_id = new_rule->vrf_id;
|
||||
memcpy(ctx->zd_ifname, new_rule->ifname, sizeof(new_rule->ifname));
|
||||
@ -3717,149 +3718,99 @@ void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx)
|
||||
* Kernel dataplane provider
|
||||
*/
|
||||
|
||||
/*
|
||||
* Handler for kernel LSP updates
|
||||
*/
|
||||
static enum zebra_dplane_result
|
||||
kernel_dplane_lsp_update(struct zebra_dplane_ctx *ctx)
|
||||
static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
return kernel_lsp_update(ctx);
|
||||
}
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
||||
/*
|
||||
* Handler for kernel pseudowire updates
|
||||
*/
|
||||
static enum zebra_dplane_result
|
||||
kernel_dplane_pw_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
|
||||
zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
|
||||
dplane_ctx_get_ifname(ctx),
|
||||
dplane_op2str(ctx->zd_op),
|
||||
dplane_ctx_get_pw_af(ctx),
|
||||
dplane_ctx_get_pw_local_label(ctx),
|
||||
dplane_ctx_get_pw_remote_label(ctx));
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
|
||||
return kernel_pw_update(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for kernel route updates
|
||||
*/
|
||||
static enum zebra_dplane_result
|
||||
kernel_dplane_route_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
|
||||
char dest_str[PREFIX_STRLEN];
|
||||
|
||||
prefix2str(dplane_ctx_get_dest(ctx),
|
||||
dest_str, sizeof(dest_str));
|
||||
case DPLANE_OP_ROUTE_INSTALL:
|
||||
case DPLANE_OP_ROUTE_UPDATE:
|
||||
case DPLANE_OP_ROUTE_DELETE:
|
||||
prefix2str(dplane_ctx_get_dest(ctx), buf, sizeof(buf));
|
||||
|
||||
zlog_debug("%u:%s Dplane route update ctx %p op %s",
|
||||
dplane_ctx_get_vrf(ctx), dest_str,
|
||||
ctx, dplane_op2str(dplane_ctx_get_op(ctx)));
|
||||
}
|
||||
dplane_ctx_get_vrf(ctx), buf, ctx,
|
||||
dplane_op2str(dplane_ctx_get_op(ctx)));
|
||||
break;
|
||||
|
||||
return kernel_route_update(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for kernel-facing interface address updates
|
||||
*/
|
||||
static enum zebra_dplane_result
|
||||
kernel_dplane_address_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
|
||||
char dest_str[PREFIX_STRLEN];
|
||||
|
||||
prefix2str(dplane_ctx_get_intf_addr(ctx), dest_str,
|
||||
sizeof(dest_str));
|
||||
|
||||
zlog_debug("Dplane intf %s, idx %u, addr %s",
|
||||
dplane_op2str(dplane_ctx_get_op(ctx)),
|
||||
dplane_ctx_get_ifindex(ctx), dest_str);
|
||||
}
|
||||
|
||||
return kernel_address_update_ctx(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* kernel_dplane_nexthop_update() - Handler for kernel nexthop updates
|
||||
*
|
||||
* @ctx: Dataplane context
|
||||
*
|
||||
* Return: Dataplane result flag
|
||||
*/
|
||||
static enum zebra_dplane_result
|
||||
kernel_dplane_nexthop_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
case DPLANE_OP_NH_UPDATE:
|
||||
case DPLANE_OP_NH_DELETE:
|
||||
zlog_debug("ID (%u) Dplane nexthop update ctx %p op %s",
|
||||
dplane_ctx_get_nhe_id(ctx), ctx,
|
||||
dplane_op2str(dplane_ctx_get_op(ctx)));
|
||||
}
|
||||
break;
|
||||
|
||||
return kernel_nexthop_update(ctx);
|
||||
}
|
||||
case DPLANE_OP_LSP_INSTALL:
|
||||
case DPLANE_OP_LSP_UPDATE:
|
||||
case DPLANE_OP_LSP_DELETE:
|
||||
break;
|
||||
|
||||
/*
|
||||
* Handler for kernel-facing EVPN MAC address updates
|
||||
*/
|
||||
static enum zebra_dplane_result
|
||||
kernel_dplane_mac_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
|
||||
char buf[ETHER_ADDR_STRLEN];
|
||||
case DPLANE_OP_PW_INSTALL:
|
||||
case DPLANE_OP_PW_UNINSTALL:
|
||||
zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
|
||||
dplane_ctx_get_ifname(ctx),
|
||||
dplane_op2str(ctx->zd_op), dplane_ctx_get_pw_af(ctx),
|
||||
dplane_ctx_get_pw_local_label(ctx),
|
||||
dplane_ctx_get_pw_remote_label(ctx));
|
||||
break;
|
||||
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
prefix2str(dplane_ctx_get_intf_addr(ctx), buf, sizeof(buf));
|
||||
|
||||
zlog_debug("Dplane intf %s, idx %u, addr %s",
|
||||
dplane_op2str(dplane_ctx_get_op(ctx)),
|
||||
dplane_ctx_get_ifindex(ctx), buf);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_MAC_INSTALL:
|
||||
case DPLANE_OP_MAC_DELETE:
|
||||
prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf,
|
||||
sizeof(buf));
|
||||
|
||||
zlog_debug("Dplane %s, mac %s, ifindex %u",
|
||||
dplane_op2str(dplane_ctx_get_op(ctx)),
|
||||
buf, dplane_ctx_get_ifindex(ctx));
|
||||
}
|
||||
|
||||
return kernel_mac_update_ctx(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for kernel-facing EVPN neighbor updates
|
||||
*/
|
||||
static enum zebra_dplane_result
|
||||
kernel_dplane_neigh_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
|
||||
char buf[PREFIX_STRLEN];
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf,
|
||||
sizeof(buf));
|
||||
|
||||
zlog_debug("Dplane %s, ip %s, ifindex %u",
|
||||
dplane_op2str(dplane_ctx_get_op(ctx)),
|
||||
buf, dplane_ctx_get_ifindex(ctx));
|
||||
}
|
||||
break;
|
||||
|
||||
return kernel_neigh_update_ctx(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for kernel PBR rule updates
|
||||
*/
|
||||
static enum zebra_dplane_result
|
||||
kernel_dplane_rule_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
|
||||
case DPLANE_OP_RULE_ADD:
|
||||
case DPLANE_OP_RULE_DELETE:
|
||||
case DPLANE_OP_RULE_UPDATE:
|
||||
zlog_debug("Dplane rule update op %s, if %s(%u), ctx %p",
|
||||
dplane_op2str(dplane_ctx_get_op(ctx)),
|
||||
dplane_ctx_get_ifname(ctx),
|
||||
dplane_ctx_get_ifindex(ctx), ctx);
|
||||
break;
|
||||
|
||||
return kernel_pbr_rule_update(ctx);
|
||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
case DPLANE_OP_ROUTE_NOTIFY:
|
||||
case DPLANE_OP_LSP_NOTIFY:
|
||||
|
||||
case DPLANE_OP_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx,
|
||||
enum zebra_dplane_result res)
|
||||
static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
enum zebra_dplane_result res = dplane_ctx_get_status(ctx);
|
||||
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
|
||||
case DPLANE_OP_ROUTE_INSTALL:
|
||||
@ -3868,6 +3819,27 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx,
|
||||
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
|
||||
atomic_fetch_add_explicit(&zdplane_info.dg_route_errors,
|
||||
1, memory_order_relaxed);
|
||||
|
||||
if ((dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE)
|
||||
&& (res == ZEBRA_DPLANE_REQUEST_SUCCESS)) {
|
||||
struct nexthop *nexthop;
|
||||
|
||||
/* Update installed nexthops to signal which have been
|
||||
* installed.
|
||||
*/
|
||||
for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
|
||||
nexthop)) {
|
||||
if (CHECK_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_ACTIVE)) {
|
||||
SET_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_FIB);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
@ -3932,11 +3904,14 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx,
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
case DPLANE_OP_ROUTE_NOTIFY:
|
||||
case DPLANE_OP_LSP_NOTIFY:
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NONE:
|
||||
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
|
||||
atomic_fetch_add_explicit(&zdplane_info.dg_other_errors,
|
||||
1, memory_order_relaxed);
|
||||
break;
|
||||
}
|
||||
|
||||
dplane_ctx_set_status(ctx, res);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3944,7 +3919,6 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx,
|
||||
*/
|
||||
static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
|
||||
{
|
||||
enum zebra_dplane_result res;
|
||||
struct zebra_dplane_ctx *ctx, *tctx;
|
||||
struct dplane_ctx_q work_list;
|
||||
int counter, limit;
|
||||
@ -3958,97 +3932,21 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
|
||||
dplane_provider_get_name(prov));
|
||||
|
||||
for (counter = 0; counter < limit; counter++) {
|
||||
|
||||
ctx = dplane_provider_dequeue_in_ctx(prov);
|
||||
if (ctx == NULL)
|
||||
break;
|
||||
|
||||
/* A previous provider plugin may have asked to skip the
|
||||
* kernel update.
|
||||
*/
|
||||
if (dplane_ctx_is_skip_kernel(ctx)) {
|
||||
res = ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
goto skip_one;
|
||||
}
|
||||
|
||||
/* Dispatch to appropriate kernel-facing apis */
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
|
||||
case DPLANE_OP_ROUTE_INSTALL:
|
||||
case DPLANE_OP_ROUTE_UPDATE:
|
||||
case DPLANE_OP_ROUTE_DELETE:
|
||||
res = kernel_dplane_route_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
case DPLANE_OP_NH_UPDATE:
|
||||
case DPLANE_OP_NH_DELETE:
|
||||
res = kernel_dplane_nexthop_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_LSP_INSTALL:
|
||||
case DPLANE_OP_LSP_UPDATE:
|
||||
case DPLANE_OP_LSP_DELETE:
|
||||
res = kernel_dplane_lsp_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_PW_INSTALL:
|
||||
case DPLANE_OP_PW_UNINSTALL:
|
||||
res = kernel_dplane_pw_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
res = kernel_dplane_address_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_MAC_INSTALL:
|
||||
case DPLANE_OP_MAC_DELETE:
|
||||
res = kernel_dplane_mac_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
res = kernel_dplane_neigh_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_RULE_ADD:
|
||||
case DPLANE_OP_RULE_DELETE:
|
||||
case DPLANE_OP_RULE_UPDATE:
|
||||
res = kernel_dplane_rule_update(ctx);
|
||||
break;
|
||||
|
||||
/* Ignore 'notifications' - no-op */
|
||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
case DPLANE_OP_ROUTE_NOTIFY:
|
||||
case DPLANE_OP_LSP_NOTIFY:
|
||||
res = ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
atomic_fetch_add_explicit(
|
||||
&zdplane_info.dg_other_errors, 1,
|
||||
memory_order_relaxed);
|
||||
|
||||
res = ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
skip_one:
|
||||
/* If the request isn't pending, we can handle the result right
|
||||
* away.
|
||||
*/
|
||||
if (res != ZEBRA_DPLANE_REQUEST_PENDING)
|
||||
kernel_dplane_handle_result(ctx, res);
|
||||
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
|
||||
kernel_dplane_log_detail(ctx);
|
||||
|
||||
TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
|
||||
}
|
||||
|
||||
kernel_update_multi(&work_list);
|
||||
|
||||
TAILQ_FOREACH_SAFE (ctx, &work_list, zd_q_entries, tctx) {
|
||||
kernel_dplane_handle_result(ctx);
|
||||
|
||||
TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
|
||||
dplane_provider_enqueue_out_ctx(prov, ctx);
|
||||
}
|
||||
@ -4093,7 +3991,6 @@ static int test_dplane_process_func(struct zebra_dplane_provider *prov)
|
||||
limit = dplane_provider_get_work_limit(prov);
|
||||
|
||||
for (counter = 0; counter < limit; counter++) {
|
||||
|
||||
ctx = dplane_provider_dequeue_in_ctx(prov);
|
||||
if (ctx == NULL)
|
||||
break;
|
||||
|
@ -90,7 +90,6 @@ enum zebra_dplane_result {
|
||||
ZEBRA_DPLANE_REQUEST_QUEUED,
|
||||
ZEBRA_DPLANE_REQUEST_SUCCESS,
|
||||
ZEBRA_DPLANE_REQUEST_FAILURE,
|
||||
ZEBRA_DPLANE_REQUEST_PENDING,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -956,9 +956,6 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
|
||||
case ZEBRA_DPLANE_REQUEST_SUCCESS:
|
||||
zvrf->lsp_installs++;
|
||||
break;
|
||||
/* Should never happen */
|
||||
case ZEBRA_DPLANE_REQUEST_PENDING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -984,10 +981,6 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
|
||||
case ZEBRA_DPLANE_REQUEST_SUCCESS:
|
||||
zvrf->lsp_removals++;
|
||||
break;
|
||||
|
||||
/* Should never happen */
|
||||
case ZEBRA_DPLANE_REQUEST_PENDING:
|
||||
break;
|
||||
}
|
||||
} else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
|
||||
zebra_nhlfe_t *nhlfe;
|
||||
@ -1031,10 +1024,6 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
|
||||
case ZEBRA_DPLANE_REQUEST_SUCCESS:
|
||||
zvrf->lsp_installs++;
|
||||
break;
|
||||
|
||||
/* Should never happen */
|
||||
case ZEBRA_DPLANE_REQUEST_PENDING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,13 +28,9 @@
|
||||
#include "zebra/zebra_mpls.h"
|
||||
#include "zebra/kernel_netlink.h"
|
||||
|
||||
/*
|
||||
* LSP forwarding update using dataplane context information.
|
||||
*/
|
||||
enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
|
||||
static ssize_t netlink_lsp_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
uint8_t nl_pkt[NL_PKT_BUF_SIZE];
|
||||
ssize_t ret = -1;
|
||||
int cmd;
|
||||
|
||||
/* Call to netlink layer based on type of update */
|
||||
@ -48,26 +44,21 @@ enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
|
||||
if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_MPLS)
|
||||
zlog_debug("LSP in-label %u: update fails, no best NHLFE",
|
||||
dplane_ctx_get_in_label(ctx));
|
||||
goto done;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd = RTM_NEWROUTE;
|
||||
} else
|
||||
/* Invalid op? */
|
||||
goto done;
|
||||
return -1;
|
||||
|
||||
ret = netlink_mpls_multipath_msg_encode(cmd, ctx, nl_pkt,
|
||||
sizeof(nl_pkt));
|
||||
if (ret <= 0)
|
||||
return ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
return netlink_mpls_multipath_msg_encode(cmd, ctx, buf, buflen);
|
||||
}
|
||||
|
||||
ret = netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
|
||||
done:
|
||||
|
||||
return (ret == 0 ?
|
||||
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
|
||||
enum netlink_msg_status netlink_put_lsp_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
return netlink_batch_add_msg(bth, ctx, netlink_lsp_msg_encoder, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -75,9 +66,10 @@ done:
|
||||
* but note that the default has been to report 'success' for pw updates
|
||||
* on unsupported platforms.
|
||||
*/
|
||||
enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx)
|
||||
enum netlink_msg_status netlink_put_pw_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
return ZEBRA_DPLANE_REQUEST_SUCCESS;
|
||||
return FRR_NETLINK_SUCCESS;
|
||||
}
|
||||
|
||||
int mpls_kernel_init(void)
|
||||
|
@ -171,13 +171,6 @@ void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset);
|
||||
void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable);
|
||||
void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable);
|
||||
|
||||
/*
|
||||
* Add, update or delete a rule from the
|
||||
* kernel, using info from a dataplane context.
|
||||
*/
|
||||
extern enum zebra_dplane_result
|
||||
kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Get to know existing PBR rules in the kernel - typically called at startup.
|
||||
*/
|
||||
|
@ -497,9 +497,6 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
|
||||
if (zvrf)
|
||||
zvrf->installs++;
|
||||
break;
|
||||
/* Should never happen */
|
||||
case ZEBRA_DPLANE_REQUEST_PENDING:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
@ -544,9 +541,6 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
|
||||
if (zvrf)
|
||||
zvrf->removals++;
|
||||
break;
|
||||
/* Should never happen */
|
||||
case ZEBRA_DPLANE_REQUEST_PENDING:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "zebra/interface.h"
|
||||
#include "northbound_cli.h"
|
||||
#include "zebra/zebra_nb.h"
|
||||
#include "zebra/kernel_netlink.h"
|
||||
|
||||
extern int allow_delete;
|
||||
|
||||
@ -3397,6 +3398,11 @@ static int config_write_protocol(struct vty *vty)
|
||||
if (!zebra_nhg_kernel_nexthops_enabled())
|
||||
vty_out(vty, "no zebra nexthop kernel enable\n");
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
/* Include netlink info */
|
||||
netlink_config_write_helper(vty);
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3719,6 +3725,44 @@ DEFUN_HIDDEN (show_frr,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
DEFUN_HIDDEN(zebra_kernel_netlink_batch_tx_buf,
|
||||
zebra_kernel_netlink_batch_tx_buf_cmd,
|
||||
"zebra kernel netlink batch-tx-buf (1-1048576) (1-1048576)",
|
||||
ZEBRA_STR
|
||||
"Zebra kernel interface\n"
|
||||
"Set Netlink parameters\n"
|
||||
"Set batch buffer size and send threshold\n"
|
||||
"Size of the buffer\n"
|
||||
"Send threshold\n")
|
||||
{
|
||||
uint32_t bufsize = 0, threshold = 0;
|
||||
|
||||
bufsize = strtoul(argv[4]->arg, NULL, 10);
|
||||
threshold = strtoul(argv[5]->arg, NULL, 10);
|
||||
|
||||
netlink_set_batch_buffer_size(bufsize, threshold, true);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_HIDDEN(no_zebra_kernel_netlink_batch_tx_buf,
|
||||
no_zebra_kernel_netlink_batch_tx_buf_cmd,
|
||||
"no zebra kernel netlink batch-tx-buf [(0-1048576)] [(0-1048576)]",
|
||||
NO_STR ZEBRA_STR
|
||||
"Zebra kernel interface\n"
|
||||
"Set Netlink parameters\n"
|
||||
"Set batch buffer size and send threshold\n"
|
||||
"Size of the buffer\n"
|
||||
"Send threshold\n")
|
||||
{
|
||||
netlink_set_batch_buffer_size(0, 0, false);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
||||
/* IP node for static routes. */
|
||||
static int zebra_ip_config(struct vty *vty);
|
||||
static struct cmd_node ip_node = {
|
||||
@ -3856,5 +3900,10 @@ void zebra_vty_init(void)
|
||||
install_element(CONFIG_NODE, &zebra_dplane_queue_limit_cmd);
|
||||
install_element(CONFIG_NODE, &no_zebra_dplane_queue_limit_cmd);
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
install_element(CONFIG_NODE, &zebra_kernel_netlink_batch_tx_buf_cmd);
|
||||
install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd);
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
||||
install_element(VIEW_NODE, &zebra_show_routing_tables_summary_cmd);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user