]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: traffic control ZAPI
authorSiger Yang <siger.yang@outlook.com>
Tue, 6 Sep 2022 07:13:23 +0000 (15:13 +0800)
committerSiger Yang <siger.yang@outlook.com>
Tue, 22 Nov 2022 14:35:35 +0000 (22:35 +0800)
This commit adds ZAPI encoders & decoders for traffic control operations, which
include tc_qdisc, tc_class and tc_filter.

Signed-off-by: Siger Yang <siger.yang@outlook.com>
lib/zclient.c
lib/zclient.h
zebra/zapi_msg.c

index fd6eb7db0d60a59c5c503a14354d6f051ed0eb44..07c7e5aea8953bfe8855e2c489fdb8a6e0c1b4c9 100644 (file)
@@ -37,6 +37,7 @@
 #include "mpls.h"
 #include "sockopt.h"
 #include "pbr.h"
+#include "tc.h"
 #include "nexthop_group.h"
 #include "lib_errors.h"
 #include "srte.h"
@@ -1649,6 +1650,96 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
        return 0;
 }
 
+int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s, struct tc_qdisc *qdisc)
+{
+       stream_reset(s);
+       zclient_create_header(s, cmd, VRF_DEFAULT);
+
+
+       stream_putl(s, 1);
+
+       stream_putl(s, qdisc->ifindex);
+       stream_putl(s, qdisc->kind);
+
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return 0;
+}
+
+int zapi_tc_class_encode(uint8_t cmd, struct stream *s, struct tc_class *class)
+{
+       stream_reset(s);
+       zclient_create_header(s, cmd, VRF_DEFAULT);
+
+       stream_putl(s, 1);
+
+       stream_putl(s, class->ifindex);
+       stream_putl(s, class->handle);
+       stream_putl(s, class->kind);
+
+       switch (class->kind) {
+       case TC_QDISC_HTB:
+               stream_putq(s, class->u.htb.rate);
+               stream_putq(s, class->u.htb.ceil);
+               break;
+       default:
+               /* not implemented */
+               break;
+       }
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return 0;
+}
+
+int zapi_tc_filter_encode(uint8_t cmd, struct stream *s,
+                         struct tc_filter *filter)
+{
+       stream_reset(s);
+       zclient_create_header(s, cmd, VRF_DEFAULT);
+
+       stream_putl(s, 1);
+
+       stream_putl(s, filter->ifindex);
+       stream_putl(s, filter->handle);
+       stream_putl(s, filter->priority);
+       stream_putl(s, filter->protocol);
+       stream_putl(s, filter->kind);
+
+       switch (filter->kind) {
+       case TC_FILTER_FLOWER:
+               stream_putl(s, filter->u.flower.filter_bm);
+               if (filter->u.flower.filter_bm & TC_FLOWER_IP_PROTOCOL)
+                       stream_putc(s, filter->u.flower.ip_proto);
+               if (filter->u.flower.filter_bm & TC_FLOWER_SRC_IP)
+                       zapi_encode_prefix(s, &filter->u.flower.src_ip,
+                                          filter->u.flower.src_ip.family);
+               if (filter->u.flower.filter_bm & TC_FLOWER_SRC_PORT) {
+                       stream_putw(s, filter->u.flower.src_port_min);
+                       stream_putw(s, filter->u.flower.src_port_max);
+               }
+               if (filter->u.flower.filter_bm & TC_FLOWER_DST_IP)
+                       zapi_encode_prefix(s, &filter->u.flower.dst_ip,
+                                          filter->u.flower.dst_ip.family);
+               if (filter->u.flower.filter_bm & TC_FLOWER_DST_PORT) {
+                       stream_putw(s, filter->u.flower.dst_port_min);
+                       stream_putw(s, filter->u.flower.dst_port_max);
+               }
+               if (filter->u.flower.filter_bm & TC_FLOWER_DSFIELD) {
+                       stream_putc(s, filter->u.flower.dsfield);
+                       stream_putc(s, filter->u.flower.dsfield_mask);
+               }
+               stream_putl(s, filter->u.flower.classid);
+               break;
+       default:
+               /* not implemented */
+               break;
+       }
+
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return 0;
+}
+
 bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id,
                            enum zapi_nhg_notify_owner *note)
 {
index 731769abf744ac595dcf5b6028f9c09761edb6a3..584a42194de5e5dc09a2cc0926e0d6710977cbb6 100644 (file)
@@ -243,6 +243,12 @@ typedef enum {
        ZEBRA_GRE_GET,
        ZEBRA_GRE_UPDATE,
        ZEBRA_GRE_SOURCE_SET,
+       ZEBRA_TC_QDISC_INSTALL,
+       ZEBRA_TC_QDISC_UNINSTALL,
+       ZEBRA_TC_CLASS_ADD,
+       ZEBRA_TC_CLASS_DELETE,
+       ZEBRA_TC_FILTER_ADD,
+       ZEBRA_TC_FILTER_DELETE,
 } zebra_message_types_t;
 
 enum zebra_error_types {
index 130fb972db70b7819c6063ba3a1339eb2cb025d0..d594512b3653fb29119c759cf3c590ab74922df6 100644 (file)
@@ -53,6 +53,7 @@
 #include "zebra/zebra_evpn_mh.h"
 #include "zebra/rt.h"
 #include "zebra/zebra_pbr.h"
+#include "zebra/zebra_tc.h"
 #include "zebra/table_manager.h"
 #include "zebra/zapi_msg.h"
 #include "zebra/zebra_errors.h"
@@ -3272,6 +3273,171 @@ stream_failure:
        return;
 }
 
+static inline void zread_tc_qdisc(ZAPI_HANDLER_ARGS)
+{
+       struct zebra_tc_qdisc qdisc;
+       struct stream *s;
+       uint32_t total, i;
+
+       s = msg;
+       STREAM_GETL(s, total);
+
+       for (i = 0; i < total; i++) {
+               memset(&qdisc, 0, sizeof(qdisc));
+
+               qdisc.sock = client->sock;
+               STREAM_GETL(s, qdisc.qdisc.ifindex);
+               STREAM_GETL(s, qdisc.qdisc.kind);
+
+               if (hdr->command == ZEBRA_TC_QDISC_INSTALL)
+                       zebra_tc_qdisc_install(&qdisc);
+               else
+                       zebra_tc_qdisc_uninstall(&qdisc);
+       }
+
+stream_failure:
+       return;
+}
+
+static inline void zread_tc_class(ZAPI_HANDLER_ARGS)
+{
+       struct zebra_tc_class class;
+       struct stream *s;
+       uint32_t total, i;
+
+       s = msg;
+       STREAM_GETL(s, total);
+
+       for (i = 0; i < total; i++) {
+               memset(&class, 0, sizeof(class));
+
+               class.sock = client->sock;
+               STREAM_GETL(s, class.class.ifindex);
+               STREAM_GETL(s, class.class.handle);
+               STREAM_GETL(s, class.class.kind);
+               STREAM_GETQ(s, class.class.u.htb.rate);
+               STREAM_GETQ(s, class.class.u.htb.ceil);
+
+               if (hdr->command == ZEBRA_TC_CLASS_ADD)
+                       zebra_tc_class_add(&class);
+               else
+                       zebra_tc_class_delete(&class);
+       }
+
+stream_failure:
+       return;
+}
+
+static inline void zread_tc_filter(ZAPI_HANDLER_ARGS)
+{
+       struct zebra_tc_filter filter;
+       struct stream *s;
+       uint32_t total, i;
+
+       s = msg;
+       STREAM_GETL(s, total);
+
+       for (i = 0; i < total; i++) {
+               memset(&filter, 0, sizeof(filter));
+
+               filter.sock = client->sock;
+               STREAM_GETL(s, filter.filter.ifindex);
+               STREAM_GETL(s, filter.filter.handle);
+               STREAM_GETL(s, filter.filter.priority);
+               STREAM_GETL(s, filter.filter.protocol);
+               STREAM_GETL(s, filter.filter.kind);
+               switch (filter.filter.kind) {
+               case TC_FILTER_FLOWER: {
+                       STREAM_GETL(s, filter.filter.u.flower.filter_bm);
+                       uint32_t filter_bm = filter.filter.u.flower.filter_bm;
+
+                       if (filter_bm & TC_FLOWER_IP_PROTOCOL)
+                               STREAM_GETC(s, filter.filter.u.flower.ip_proto);
+                       if (filter_bm & TC_FLOWER_SRC_IP) {
+                               STREAM_GETC(
+                                       s,
+                                       filter.filter.u.flower.src_ip.family);
+                               STREAM_GETC(s, filter.filter.u.flower.src_ip
+                                                      .prefixlen);
+                               STREAM_GET(
+                                       &filter.filter.u.flower.src_ip.u.prefix,
+                                       s,
+                                       prefix_blen(&filter.filter.u.flower
+                                                            .src_ip));
+
+                               if (!(filter.filter.u.flower.src_ip.family ==
+                                             AF_INET ||
+                                     filter.filter.u.flower.src_ip.family ==
+                                             AF_INET6)) {
+                                       zlog_warn(
+                                               "Unsupported TC source IP family: %s (%hhu)",
+                                               family2str(
+                                                       filter.filter.u.flower
+                                                               .src_ip.family),
+                                               filter.filter.u.flower.src_ip
+                                                       .family);
+                                       return;
+                               }
+                       }
+                       if (filter_bm & TC_FLOWER_SRC_PORT) {
+                               STREAM_GETW(
+                                       s, filter.filter.u.flower.src_port_min);
+                               STREAM_GETW(
+                                       s, filter.filter.u.flower.src_port_max);
+                       }
+                       if (filter_bm & TC_FLOWER_DST_IP) {
+                               STREAM_GETC(
+                                       s,
+                                       filter.filter.u.flower.dst_ip.family);
+                               STREAM_GETC(s, filter.filter.u.flower.dst_ip
+                                                      .prefixlen);
+                               STREAM_GET(
+                                       &filter.filter.u.flower.dst_ip.u.prefix,
+                                       s,
+                                       prefix_blen(&filter.filter.u.flower
+                                                            .dst_ip));
+                               if (!(filter.filter.u.flower.dst_ip.family ==
+                                             AF_INET ||
+                                     filter.filter.u.flower.dst_ip.family ==
+                                             AF_INET6)) {
+                                       zlog_warn(
+                                               "Unsupported TC destination IP family: %s (%hhu)",
+                                               family2str(
+                                                       filter.filter.u.flower
+                                                               .dst_ip.family),
+                                               filter.filter.u.flower.dst_ip
+                                                       .family);
+                                       return;
+                               }
+                       }
+                       if (filter_bm & TC_FLOWER_DST_PORT) {
+                               STREAM_GETW(
+                                       s, filter.filter.u.flower.dst_port_min);
+                               STREAM_GETW(
+                                       s, filter.filter.u.flower.dst_port_max);
+                       }
+                       if (filter_bm & TC_FLOWER_DSFIELD) {
+                               STREAM_GETC(s, filter.filter.u.flower.dsfield);
+                               STREAM_GETC(
+                                       s, filter.filter.u.flower.dsfield_mask);
+                       }
+                       STREAM_GETL(s, filter.filter.u.flower.classid);
+                       break;
+               }
+               default:
+                       break;
+               }
+
+               if (hdr->command == ZEBRA_TC_FILTER_ADD)
+                       zebra_tc_filter_add(&filter);
+               else
+                       zebra_tc_filter_delete(&filter);
+       }
+
+stream_failure:
+       return;
+}
+
 static inline void zread_ipset(ZAPI_HANDLER_ARGS)
 {
        struct zebra_pbr_ipset zpi;
@@ -3772,6 +3938,12 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_CONFIGURE_ARP] = zebra_configure_arp,
        [ZEBRA_GRE_GET] = zebra_gre_get,
        [ZEBRA_GRE_SOURCE_SET] = zebra_gre_source_set,
+       [ZEBRA_TC_QDISC_INSTALL] = zread_tc_qdisc,
+       [ZEBRA_TC_QDISC_UNINSTALL] = zread_tc_qdisc,
+       [ZEBRA_TC_CLASS_ADD] = zread_tc_class,
+       [ZEBRA_TC_CLASS_DELETE] = zread_tc_class,
+       [ZEBRA_TC_FILTER_ADD] = zread_tc_filter,
+       [ZEBRA_TC_FILTER_DELETE] = zread_tc_filter,
 };
 
 /*