Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/sched: Retire rsvp classifier

The rsvp classifier has served us well for about a quarter of a century but has
has not been getting much maintenance attention due to lack of known users.

Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Acked-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Jamal Hadi Salim and committed by
Paolo Abeni
265b4da8 8c710f75

-1059
-10
include/net/tc_wrapper.h
··· 152 152 TC_INDIRECT_FILTER_DECLARE(fw_classify); 153 153 TC_INDIRECT_FILTER_DECLARE(mall_classify); 154 154 TC_INDIRECT_FILTER_DECLARE(route4_classify); 155 - TC_INDIRECT_FILTER_DECLARE(rsvp_classify); 156 - TC_INDIRECT_FILTER_DECLARE(rsvp6_classify); 157 155 TC_INDIRECT_FILTER_DECLARE(u32_classify); 158 156 159 157 static inline int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp, ··· 195 197 #if IS_BUILTIN(CONFIG_NET_CLS_ROUTE4) 196 198 if (tp->classify == route4_classify) 197 199 return route4_classify(skb, tp, res); 198 - #endif 199 - #if IS_BUILTIN(CONFIG_NET_CLS_RSVP) 200 - if (tp->classify == rsvp_classify) 201 - return rsvp_classify(skb, tp, res); 202 - #endif 203 - #if IS_BUILTIN(CONFIG_NET_CLS_RSVP6) 204 - if (tp->classify == rsvp6_classify) 205 - return rsvp6_classify(skb, tp, res); 206 200 #endif 207 201 208 202 skip:
-28
net/sched/Kconfig
··· 513 513 help 514 514 Say Y here to be able to use netfilter marks as u32 key. 515 515 516 - config NET_CLS_RSVP 517 - tristate "IPv4 Resource Reservation Protocol (RSVP)" 518 - select NET_CLS 519 - help 520 - The Resource Reservation Protocol (RSVP) permits end systems to 521 - request a minimum and maximum data flow rate for a connection; this 522 - is important for real time data such as streaming sound or video. 523 - 524 - Say Y here if you want to be able to classify outgoing packets based 525 - on their RSVP requests. 526 - 527 - To compile this code as a module, choose M here: the 528 - module will be called cls_rsvp. 529 - 530 - config NET_CLS_RSVP6 531 - tristate "IPv6 Resource Reservation Protocol (RSVP6)" 532 - select NET_CLS 533 - help 534 - The Resource Reservation Protocol (RSVP) permits end systems to 535 - request a minimum and maximum data flow rate for a connection; this 536 - is important for real time data such as streaming sound or video. 537 - 538 - Say Y here if you want to be able to classify outgoing packets based 539 - on their RSVP requests and you are using the IPv6 protocol. 540 - 541 - To compile this code as a module, choose M here: the 542 - module will be called cls_rsvp6. 543 - 544 516 config NET_CLS_FLOW 545 517 tristate "Flow classifier" 546 518 select NET_CLS
-2
net/sched/Makefile
··· 67 67 obj-$(CONFIG_NET_CLS_U32) += cls_u32.o 68 68 obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o 69 69 obj-$(CONFIG_NET_CLS_FW) += cls_fw.o 70 - obj-$(CONFIG_NET_CLS_RSVP) += cls_rsvp.o 71 - obj-$(CONFIG_NET_CLS_RSVP6) += cls_rsvp6.o 72 70 obj-$(CONFIG_NET_CLS_BASIC) += cls_basic.o 73 71 obj-$(CONFIG_NET_CLS_FLOW) += cls_flow.o 74 72 obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o
-26
net/sched/cls_rsvp.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* 3 - * net/sched/cls_rsvp.c Special RSVP packet classifier for IPv4. 4 - * 5 - * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 6 - */ 7 - 8 - #include <linux/module.h> 9 - #include <linux/types.h> 10 - #include <linux/kernel.h> 11 - #include <linux/string.h> 12 - #include <linux/errno.h> 13 - #include <linux/skbuff.h> 14 - #include <net/ip.h> 15 - #include <net/netlink.h> 16 - #include <net/act_api.h> 17 - #include <net/pkt_cls.h> 18 - #include <net/tc_wrapper.h> 19 - 20 - #define RSVP_DST_LEN 1 21 - #define RSVP_ID "rsvp" 22 - #define RSVP_OPS cls_rsvp_ops 23 - #define RSVP_CLS rsvp_classify 24 - 25 - #include "cls_rsvp.h" 26 - MODULE_LICENSE("GPL");
-764
net/sched/cls_rsvp.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 - /* 3 - * net/sched/cls_rsvp.h Template file for RSVPv[46] classifiers. 4 - * 5 - * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 6 - */ 7 - 8 - /* 9 - Comparing to general packet classification problem, 10 - RSVP needs only several relatively simple rules: 11 - 12 - * (dst, protocol) are always specified, 13 - so that we are able to hash them. 14 - * src may be exact, or may be wildcard, so that 15 - we can keep a hash table plus one wildcard entry. 16 - * source port (or flow label) is important only if src is given. 17 - 18 - IMPLEMENTATION. 19 - 20 - We use a two level hash table: The top level is keyed by 21 - destination address and protocol ID, every bucket contains a list 22 - of "rsvp sessions", identified by destination address, protocol and 23 - DPI(="Destination Port ID"): triple (key, mask, offset). 24 - 25 - Every bucket has a smaller hash table keyed by source address 26 - (cf. RSVP flowspec) and one wildcard entry for wildcard reservations. 27 - Every bucket is again a list of "RSVP flows", selected by 28 - source address and SPI(="Source Port ID" here rather than 29 - "security parameter index"): triple (key, mask, offset). 30 - 31 - 32 - NOTE 1. All the packets with IPv6 extension headers (but AH and ESP) 33 - and all fragmented packets go to the best-effort traffic class. 34 - 35 - 36 - NOTE 2. Two "port id"'s seems to be redundant, rfc2207 requires 37 - only one "Generalized Port Identifier". So that for classic 38 - ah, esp (and udp,tcp) both *pi should coincide or one of them 39 - should be wildcard. 40 - 41 - At first sight, this redundancy is just a waste of CPU 42 - resources. But DPI and SPI add the possibility to assign different 43 - priorities to GPIs. Look also at note 4 about tunnels below. 44 - 45 - 46 - NOTE 3. One complication is the case of tunneled packets. 47 - We implement it as following: if the first lookup 48 - matches a special session with "tunnelhdr" value not zero, 49 - flowid doesn't contain the true flow ID, but the tunnel ID (1...255). 50 - In this case, we pull tunnelhdr bytes and restart lookup 51 - with tunnel ID added to the list of keys. Simple and stupid 8)8) 52 - It's enough for PIMREG and IPIP. 53 - 54 - 55 - NOTE 4. Two GPIs make it possible to parse even GRE packets. 56 - F.e. DPI can select ETH_P_IP (and necessary flags to make 57 - tunnelhdr correct) in GRE protocol field and SPI matches 58 - GRE key. Is it not nice? 8)8) 59 - 60 - 61 - Well, as result, despite its simplicity, we get a pretty 62 - powerful classification engine. */ 63 - 64 - 65 - struct rsvp_head { 66 - u32 tmap[256/32]; 67 - u32 hgenerator; 68 - u8 tgenerator; 69 - struct rsvp_session __rcu *ht[256]; 70 - struct rcu_head rcu; 71 - }; 72 - 73 - struct rsvp_session { 74 - struct rsvp_session __rcu *next; 75 - __be32 dst[RSVP_DST_LEN]; 76 - struct tc_rsvp_gpi dpi; 77 - u8 protocol; 78 - u8 tunnelid; 79 - /* 16 (src,sport) hash slots, and one wildcard source slot */ 80 - struct rsvp_filter __rcu *ht[16 + 1]; 81 - struct rcu_head rcu; 82 - }; 83 - 84 - 85 - struct rsvp_filter { 86 - struct rsvp_filter __rcu *next; 87 - __be32 src[RSVP_DST_LEN]; 88 - struct tc_rsvp_gpi spi; 89 - u8 tunnelhdr; 90 - 91 - struct tcf_result res; 92 - struct tcf_exts exts; 93 - 94 - u32 handle; 95 - struct rsvp_session *sess; 96 - struct rcu_work rwork; 97 - }; 98 - 99 - static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid) 100 - { 101 - unsigned int h = (__force __u32)dst[RSVP_DST_LEN - 1]; 102 - 103 - h ^= h>>16; 104 - h ^= h>>8; 105 - return (h ^ protocol ^ tunnelid) & 0xFF; 106 - } 107 - 108 - static inline unsigned int hash_src(__be32 *src) 109 - { 110 - unsigned int h = (__force __u32)src[RSVP_DST_LEN-1]; 111 - 112 - h ^= h>>16; 113 - h ^= h>>8; 114 - h ^= h>>4; 115 - return h & 0xF; 116 - } 117 - 118 - #define RSVP_APPLY_RESULT() \ 119 - { \ 120 - int r = tcf_exts_exec(skb, &f->exts, res); \ 121 - if (r < 0) \ 122 - continue; \ 123 - else if (r > 0) \ 124 - return r; \ 125 - } 126 - 127 - TC_INDIRECT_SCOPE int RSVP_CLS(struct sk_buff *skb, const struct tcf_proto *tp, 128 - struct tcf_result *res) 129 - { 130 - struct rsvp_head *head = rcu_dereference_bh(tp->root); 131 - struct rsvp_session *s; 132 - struct rsvp_filter *f; 133 - unsigned int h1, h2; 134 - __be32 *dst, *src; 135 - u8 protocol; 136 - u8 tunnelid = 0; 137 - u8 *xprt; 138 - #if RSVP_DST_LEN == 4 139 - struct ipv6hdr *nhptr; 140 - 141 - if (!pskb_network_may_pull(skb, sizeof(*nhptr))) 142 - return -1; 143 - nhptr = ipv6_hdr(skb); 144 - #else 145 - struct iphdr *nhptr; 146 - 147 - if (!pskb_network_may_pull(skb, sizeof(*nhptr))) 148 - return -1; 149 - nhptr = ip_hdr(skb); 150 - #endif 151 - restart: 152 - 153 - #if RSVP_DST_LEN == 4 154 - src = &nhptr->saddr.s6_addr32[0]; 155 - dst = &nhptr->daddr.s6_addr32[0]; 156 - protocol = nhptr->nexthdr; 157 - xprt = ((u8 *)nhptr) + sizeof(struct ipv6hdr); 158 - #else 159 - src = &nhptr->saddr; 160 - dst = &nhptr->daddr; 161 - protocol = nhptr->protocol; 162 - xprt = ((u8 *)nhptr) + (nhptr->ihl<<2); 163 - if (ip_is_fragment(nhptr)) 164 - return -1; 165 - #endif 166 - 167 - h1 = hash_dst(dst, protocol, tunnelid); 168 - h2 = hash_src(src); 169 - 170 - for (s = rcu_dereference_bh(head->ht[h1]); s; 171 - s = rcu_dereference_bh(s->next)) { 172 - if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN - 1] && 173 - protocol == s->protocol && 174 - !(s->dpi.mask & 175 - (*(u32 *)(xprt + s->dpi.offset) ^ s->dpi.key)) && 176 - #if RSVP_DST_LEN == 4 177 - dst[0] == s->dst[0] && 178 - dst[1] == s->dst[1] && 179 - dst[2] == s->dst[2] && 180 - #endif 181 - tunnelid == s->tunnelid) { 182 - 183 - for (f = rcu_dereference_bh(s->ht[h2]); f; 184 - f = rcu_dereference_bh(f->next)) { 185 - if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN - 1] && 186 - !(f->spi.mask & (*(u32 *)(xprt + f->spi.offset) ^ f->spi.key)) 187 - #if RSVP_DST_LEN == 4 188 - && 189 - src[0] == f->src[0] && 190 - src[1] == f->src[1] && 191 - src[2] == f->src[2] 192 - #endif 193 - ) { 194 - *res = f->res; 195 - RSVP_APPLY_RESULT(); 196 - 197 - matched: 198 - if (f->tunnelhdr == 0) 199 - return 0; 200 - 201 - tunnelid = f->res.classid; 202 - nhptr = (void *)(xprt + f->tunnelhdr - sizeof(*nhptr)); 203 - goto restart; 204 - } 205 - } 206 - 207 - /* And wildcard bucket... */ 208 - for (f = rcu_dereference_bh(s->ht[16]); f; 209 - f = rcu_dereference_bh(f->next)) { 210 - *res = f->res; 211 - RSVP_APPLY_RESULT(); 212 - goto matched; 213 - } 214 - return -1; 215 - } 216 - } 217 - return -1; 218 - } 219 - 220 - static void rsvp_replace(struct tcf_proto *tp, struct rsvp_filter *n, u32 h) 221 - { 222 - struct rsvp_head *head = rtnl_dereference(tp->root); 223 - struct rsvp_session *s; 224 - struct rsvp_filter __rcu **ins; 225 - struct rsvp_filter *pins; 226 - unsigned int h1 = h & 0xFF; 227 - unsigned int h2 = (h >> 8) & 0xFF; 228 - 229 - for (s = rtnl_dereference(head->ht[h1]); s; 230 - s = rtnl_dereference(s->next)) { 231 - for (ins = &s->ht[h2], pins = rtnl_dereference(*ins); ; 232 - ins = &pins->next, pins = rtnl_dereference(*ins)) { 233 - if (pins->handle == h) { 234 - RCU_INIT_POINTER(n->next, pins->next); 235 - rcu_assign_pointer(*ins, n); 236 - return; 237 - } 238 - } 239 - } 240 - 241 - /* Something went wrong if we are trying to replace a non-existent 242 - * node. Mind as well halt instead of silently failing. 243 - */ 244 - BUG_ON(1); 245 - } 246 - 247 - static void *rsvp_get(struct tcf_proto *tp, u32 handle) 248 - { 249 - struct rsvp_head *head = rtnl_dereference(tp->root); 250 - struct rsvp_session *s; 251 - struct rsvp_filter *f; 252 - unsigned int h1 = handle & 0xFF; 253 - unsigned int h2 = (handle >> 8) & 0xFF; 254 - 255 - if (h2 > 16) 256 - return NULL; 257 - 258 - for (s = rtnl_dereference(head->ht[h1]); s; 259 - s = rtnl_dereference(s->next)) { 260 - for (f = rtnl_dereference(s->ht[h2]); f; 261 - f = rtnl_dereference(f->next)) { 262 - if (f->handle == handle) 263 - return f; 264 - } 265 - } 266 - return NULL; 267 - } 268 - 269 - static int rsvp_init(struct tcf_proto *tp) 270 - { 271 - struct rsvp_head *data; 272 - 273 - data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL); 274 - if (data) { 275 - rcu_assign_pointer(tp->root, data); 276 - return 0; 277 - } 278 - return -ENOBUFS; 279 - } 280 - 281 - static void __rsvp_delete_filter(struct rsvp_filter *f) 282 - { 283 - tcf_exts_destroy(&f->exts); 284 - tcf_exts_put_net(&f->exts); 285 - kfree(f); 286 - } 287 - 288 - static void rsvp_delete_filter_work(struct work_struct *work) 289 - { 290 - struct rsvp_filter *f = container_of(to_rcu_work(work), 291 - struct rsvp_filter, 292 - rwork); 293 - rtnl_lock(); 294 - __rsvp_delete_filter(f); 295 - rtnl_unlock(); 296 - } 297 - 298 - static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) 299 - { 300 - tcf_unbind_filter(tp, &f->res); 301 - /* all classifiers are required to call tcf_exts_destroy() after rcu 302 - * grace period, since converted-to-rcu actions are relying on that 303 - * in cleanup() callback 304 - */ 305 - if (tcf_exts_get_net(&f->exts)) 306 - tcf_queue_work(&f->rwork, rsvp_delete_filter_work); 307 - else 308 - __rsvp_delete_filter(f); 309 - } 310 - 311 - static void rsvp_destroy(struct tcf_proto *tp, bool rtnl_held, 312 - struct netlink_ext_ack *extack) 313 - { 314 - struct rsvp_head *data = rtnl_dereference(tp->root); 315 - int h1, h2; 316 - 317 - if (data == NULL) 318 - return; 319 - 320 - for (h1 = 0; h1 < 256; h1++) { 321 - struct rsvp_session *s; 322 - 323 - while ((s = rtnl_dereference(data->ht[h1])) != NULL) { 324 - RCU_INIT_POINTER(data->ht[h1], s->next); 325 - 326 - for (h2 = 0; h2 <= 16; h2++) { 327 - struct rsvp_filter *f; 328 - 329 - while ((f = rtnl_dereference(s->ht[h2])) != NULL) { 330 - rcu_assign_pointer(s->ht[h2], f->next); 331 - rsvp_delete_filter(tp, f); 332 - } 333 - } 334 - kfree_rcu(s, rcu); 335 - } 336 - } 337 - kfree_rcu(data, rcu); 338 - } 339 - 340 - static int rsvp_delete(struct tcf_proto *tp, void *arg, bool *last, 341 - bool rtnl_held, struct netlink_ext_ack *extack) 342 - { 343 - struct rsvp_head *head = rtnl_dereference(tp->root); 344 - struct rsvp_filter *nfp, *f = arg; 345 - struct rsvp_filter __rcu **fp; 346 - unsigned int h = f->handle; 347 - struct rsvp_session __rcu **sp; 348 - struct rsvp_session *nsp, *s = f->sess; 349 - int i, h1; 350 - 351 - fp = &s->ht[(h >> 8) & 0xFF]; 352 - for (nfp = rtnl_dereference(*fp); nfp; 353 - fp = &nfp->next, nfp = rtnl_dereference(*fp)) { 354 - if (nfp == f) { 355 - RCU_INIT_POINTER(*fp, f->next); 356 - rsvp_delete_filter(tp, f); 357 - 358 - /* Strip tree */ 359 - 360 - for (i = 0; i <= 16; i++) 361 - if (s->ht[i]) 362 - goto out; 363 - 364 - /* OK, session has no flows */ 365 - sp = &head->ht[h & 0xFF]; 366 - for (nsp = rtnl_dereference(*sp); nsp; 367 - sp = &nsp->next, nsp = rtnl_dereference(*sp)) { 368 - if (nsp == s) { 369 - RCU_INIT_POINTER(*sp, s->next); 370 - kfree_rcu(s, rcu); 371 - goto out; 372 - } 373 - } 374 - 375 - break; 376 - } 377 - } 378 - 379 - out: 380 - *last = true; 381 - for (h1 = 0; h1 < 256; h1++) { 382 - if (rcu_access_pointer(head->ht[h1])) { 383 - *last = false; 384 - break; 385 - } 386 - } 387 - 388 - return 0; 389 - } 390 - 391 - static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt) 392 - { 393 - struct rsvp_head *data = rtnl_dereference(tp->root); 394 - int i = 0xFFFF; 395 - 396 - while (i-- > 0) { 397 - u32 h; 398 - 399 - if ((data->hgenerator += 0x10000) == 0) 400 - data->hgenerator = 0x10000; 401 - h = data->hgenerator|salt; 402 - if (!rsvp_get(tp, h)) 403 - return h; 404 - } 405 - return 0; 406 - } 407 - 408 - static int tunnel_bts(struct rsvp_head *data) 409 - { 410 - int n = data->tgenerator >> 5; 411 - u32 b = 1 << (data->tgenerator & 0x1F); 412 - 413 - if (data->tmap[n] & b) 414 - return 0; 415 - data->tmap[n] |= b; 416 - return 1; 417 - } 418 - 419 - static void tunnel_recycle(struct rsvp_head *data) 420 - { 421 - struct rsvp_session __rcu **sht = data->ht; 422 - u32 tmap[256/32]; 423 - int h1, h2; 424 - 425 - memset(tmap, 0, sizeof(tmap)); 426 - 427 - for (h1 = 0; h1 < 256; h1++) { 428 - struct rsvp_session *s; 429 - for (s = rtnl_dereference(sht[h1]); s; 430 - s = rtnl_dereference(s->next)) { 431 - for (h2 = 0; h2 <= 16; h2++) { 432 - struct rsvp_filter *f; 433 - 434 - for (f = rtnl_dereference(s->ht[h2]); f; 435 - f = rtnl_dereference(f->next)) { 436 - if (f->tunnelhdr == 0) 437 - continue; 438 - data->tgenerator = f->res.classid; 439 - tunnel_bts(data); 440 - } 441 - } 442 - } 443 - } 444 - 445 - memcpy(data->tmap, tmap, sizeof(tmap)); 446 - } 447 - 448 - static u32 gen_tunnel(struct rsvp_head *data) 449 - { 450 - int i, k; 451 - 452 - for (k = 0; k < 2; k++) { 453 - for (i = 255; i > 0; i--) { 454 - if (++data->tgenerator == 0) 455 - data->tgenerator = 1; 456 - if (tunnel_bts(data)) 457 - return data->tgenerator; 458 - } 459 - tunnel_recycle(data); 460 - } 461 - return 0; 462 - } 463 - 464 - static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = { 465 - [TCA_RSVP_CLASSID] = { .type = NLA_U32 }, 466 - [TCA_RSVP_DST] = { .len = RSVP_DST_LEN * sizeof(u32) }, 467 - [TCA_RSVP_SRC] = { .len = RSVP_DST_LEN * sizeof(u32) }, 468 - [TCA_RSVP_PINFO] = { .len = sizeof(struct tc_rsvp_pinfo) }, 469 - }; 470 - 471 - static int rsvp_change(struct net *net, struct sk_buff *in_skb, 472 - struct tcf_proto *tp, unsigned long base, 473 - u32 handle, struct nlattr **tca, 474 - void **arg, u32 flags, 475 - struct netlink_ext_ack *extack) 476 - { 477 - struct rsvp_head *data = rtnl_dereference(tp->root); 478 - struct rsvp_filter *f, *nfp; 479 - struct rsvp_filter __rcu **fp; 480 - struct rsvp_session *nsp, *s; 481 - struct rsvp_session __rcu **sp; 482 - struct tc_rsvp_pinfo *pinfo = NULL; 483 - struct nlattr *opt = tca[TCA_OPTIONS]; 484 - struct nlattr *tb[TCA_RSVP_MAX + 1]; 485 - struct tcf_exts e; 486 - unsigned int h1, h2; 487 - __be32 *dst; 488 - int err; 489 - 490 - if (opt == NULL) 491 - return handle ? -EINVAL : 0; 492 - 493 - err = nla_parse_nested_deprecated(tb, TCA_RSVP_MAX, opt, rsvp_policy, 494 - NULL); 495 - if (err < 0) 496 - return err; 497 - 498 - err = tcf_exts_init(&e, net, TCA_RSVP_ACT, TCA_RSVP_POLICE); 499 - if (err < 0) 500 - return err; 501 - err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, flags, 502 - extack); 503 - if (err < 0) 504 - goto errout2; 505 - 506 - f = *arg; 507 - if (f) { 508 - /* Node exists: adjust only classid */ 509 - struct rsvp_filter *n; 510 - 511 - if (f->handle != handle && handle) 512 - goto errout2; 513 - 514 - n = kmemdup(f, sizeof(*f), GFP_KERNEL); 515 - if (!n) { 516 - err = -ENOMEM; 517 - goto errout2; 518 - } 519 - 520 - err = tcf_exts_init(&n->exts, net, TCA_RSVP_ACT, 521 - TCA_RSVP_POLICE); 522 - if (err < 0) { 523 - kfree(n); 524 - goto errout2; 525 - } 526 - 527 - if (tb[TCA_RSVP_CLASSID]) { 528 - n->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]); 529 - tcf_bind_filter(tp, &n->res, base); 530 - } 531 - 532 - tcf_exts_change(&n->exts, &e); 533 - rsvp_replace(tp, n, handle); 534 - return 0; 535 - } 536 - 537 - /* Now more serious part... */ 538 - err = -EINVAL; 539 - if (handle) 540 - goto errout2; 541 - if (tb[TCA_RSVP_DST] == NULL) 542 - goto errout2; 543 - 544 - err = -ENOBUFS; 545 - f = kzalloc(sizeof(struct rsvp_filter), GFP_KERNEL); 546 - if (f == NULL) 547 - goto errout2; 548 - 549 - err = tcf_exts_init(&f->exts, net, TCA_RSVP_ACT, TCA_RSVP_POLICE); 550 - if (err < 0) 551 - goto errout; 552 - h2 = 16; 553 - if (tb[TCA_RSVP_SRC]) { 554 - memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src)); 555 - h2 = hash_src(f->src); 556 - } 557 - if (tb[TCA_RSVP_PINFO]) { 558 - pinfo = nla_data(tb[TCA_RSVP_PINFO]); 559 - f->spi = pinfo->spi; 560 - f->tunnelhdr = pinfo->tunnelhdr; 561 - } 562 - if (tb[TCA_RSVP_CLASSID]) 563 - f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]); 564 - 565 - dst = nla_data(tb[TCA_RSVP_DST]); 566 - h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0); 567 - 568 - err = -ENOMEM; 569 - if ((f->handle = gen_handle(tp, h1 | (h2<<8))) == 0) 570 - goto errout; 571 - 572 - if (f->tunnelhdr) { 573 - err = -EINVAL; 574 - if (f->res.classid > 255) 575 - goto errout; 576 - 577 - err = -ENOMEM; 578 - if (f->res.classid == 0 && 579 - (f->res.classid = gen_tunnel(data)) == 0) 580 - goto errout; 581 - } 582 - 583 - for (sp = &data->ht[h1]; 584 - (s = rtnl_dereference(*sp)) != NULL; 585 - sp = &s->next) { 586 - if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] && 587 - pinfo && pinfo->protocol == s->protocol && 588 - memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 && 589 - #if RSVP_DST_LEN == 4 590 - dst[0] == s->dst[0] && 591 - dst[1] == s->dst[1] && 592 - dst[2] == s->dst[2] && 593 - #endif 594 - pinfo->tunnelid == s->tunnelid) { 595 - 596 - insert: 597 - /* OK, we found appropriate session */ 598 - 599 - fp = &s->ht[h2]; 600 - 601 - f->sess = s; 602 - if (f->tunnelhdr == 0) 603 - tcf_bind_filter(tp, &f->res, base); 604 - 605 - tcf_exts_change(&f->exts, &e); 606 - 607 - fp = &s->ht[h2]; 608 - for (nfp = rtnl_dereference(*fp); nfp; 609 - fp = &nfp->next, nfp = rtnl_dereference(*fp)) { 610 - __u32 mask = nfp->spi.mask & f->spi.mask; 611 - 612 - if (mask != f->spi.mask) 613 - break; 614 - } 615 - RCU_INIT_POINTER(f->next, nfp); 616 - rcu_assign_pointer(*fp, f); 617 - 618 - *arg = f; 619 - return 0; 620 - } 621 - } 622 - 623 - /* No session found. Create new one. */ 624 - 625 - err = -ENOBUFS; 626 - s = kzalloc(sizeof(struct rsvp_session), GFP_KERNEL); 627 - if (s == NULL) 628 - goto errout; 629 - memcpy(s->dst, dst, sizeof(s->dst)); 630 - 631 - if (pinfo) { 632 - s->dpi = pinfo->dpi; 633 - s->protocol = pinfo->protocol; 634 - s->tunnelid = pinfo->tunnelid; 635 - } 636 - sp = &data->ht[h1]; 637 - for (nsp = rtnl_dereference(*sp); nsp; 638 - sp = &nsp->next, nsp = rtnl_dereference(*sp)) { 639 - if ((nsp->dpi.mask & s->dpi.mask) != s->dpi.mask) 640 - break; 641 - } 642 - RCU_INIT_POINTER(s->next, nsp); 643 - rcu_assign_pointer(*sp, s); 644 - 645 - goto insert; 646 - 647 - errout: 648 - tcf_exts_destroy(&f->exts); 649 - kfree(f); 650 - errout2: 651 - tcf_exts_destroy(&e); 652 - return err; 653 - } 654 - 655 - static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg, 656 - bool rtnl_held) 657 - { 658 - struct rsvp_head *head = rtnl_dereference(tp->root); 659 - unsigned int h, h1; 660 - 661 - if (arg->stop) 662 - return; 663 - 664 - for (h = 0; h < 256; h++) { 665 - struct rsvp_session *s; 666 - 667 - for (s = rtnl_dereference(head->ht[h]); s; 668 - s = rtnl_dereference(s->next)) { 669 - for (h1 = 0; h1 <= 16; h1++) { 670 - struct rsvp_filter *f; 671 - 672 - for (f = rtnl_dereference(s->ht[h1]); f; 673 - f = rtnl_dereference(f->next)) { 674 - if (!tc_cls_stats_dump(tp, arg, f)) 675 - return; 676 - } 677 - } 678 - } 679 - } 680 - } 681 - 682 - static int rsvp_dump(struct net *net, struct tcf_proto *tp, void *fh, 683 - struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) 684 - { 685 - struct rsvp_filter *f = fh; 686 - struct rsvp_session *s; 687 - struct nlattr *nest; 688 - struct tc_rsvp_pinfo pinfo; 689 - 690 - if (f == NULL) 691 - return skb->len; 692 - s = f->sess; 693 - 694 - t->tcm_handle = f->handle; 695 - 696 - nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 697 - if (nest == NULL) 698 - goto nla_put_failure; 699 - 700 - if (nla_put(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst)) 701 - goto nla_put_failure; 702 - pinfo.dpi = s->dpi; 703 - pinfo.spi = f->spi; 704 - pinfo.protocol = s->protocol; 705 - pinfo.tunnelid = s->tunnelid; 706 - pinfo.tunnelhdr = f->tunnelhdr; 707 - pinfo.pad = 0; 708 - if (nla_put(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo)) 709 - goto nla_put_failure; 710 - if (f->res.classid && 711 - nla_put_u32(skb, TCA_RSVP_CLASSID, f->res.classid)) 712 - goto nla_put_failure; 713 - if (((f->handle >> 8) & 0xFF) != 16 && 714 - nla_put(skb, TCA_RSVP_SRC, sizeof(f->src), f->src)) 715 - goto nla_put_failure; 716 - 717 - if (tcf_exts_dump(skb, &f->exts) < 0) 718 - goto nla_put_failure; 719 - 720 - nla_nest_end(skb, nest); 721 - 722 - if (tcf_exts_dump_stats(skb, &f->exts) < 0) 723 - goto nla_put_failure; 724 - return skb->len; 725 - 726 - nla_put_failure: 727 - nla_nest_cancel(skb, nest); 728 - return -1; 729 - } 730 - 731 - static void rsvp_bind_class(void *fh, u32 classid, unsigned long cl, void *q, 732 - unsigned long base) 733 - { 734 - struct rsvp_filter *f = fh; 735 - 736 - tc_cls_bind_class(classid, cl, q, &f->res, base); 737 - } 738 - 739 - static struct tcf_proto_ops RSVP_OPS __read_mostly = { 740 - .kind = RSVP_ID, 741 - .classify = RSVP_CLS, 742 - .init = rsvp_init, 743 - .destroy = rsvp_destroy, 744 - .get = rsvp_get, 745 - .change = rsvp_change, 746 - .delete = rsvp_delete, 747 - .walk = rsvp_walk, 748 - .dump = rsvp_dump, 749 - .bind_class = rsvp_bind_class, 750 - .owner = THIS_MODULE, 751 - }; 752 - 753 - static int __init init_rsvp(void) 754 - { 755 - return register_tcf_proto_ops(&RSVP_OPS); 756 - } 757 - 758 - static void __exit exit_rsvp(void) 759 - { 760 - unregister_tcf_proto_ops(&RSVP_OPS); 761 - } 762 - 763 - module_init(init_rsvp) 764 - module_exit(exit_rsvp)
-26
net/sched/cls_rsvp6.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* 3 - * net/sched/cls_rsvp6.c Special RSVP packet classifier for IPv6. 4 - * 5 - * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 6 - */ 7 - 8 - #include <linux/module.h> 9 - #include <linux/types.h> 10 - #include <linux/kernel.h> 11 - #include <linux/string.h> 12 - #include <linux/errno.h> 13 - #include <linux/ipv6.h> 14 - #include <linux/skbuff.h> 15 - #include <net/act_api.h> 16 - #include <net/pkt_cls.h> 17 - #include <net/netlink.h> 18 - #include <net/tc_wrapper.h> 19 - 20 - #define RSVP_DST_LEN 4 21 - #define RSVP_ID "rsvp6" 22 - #define RSVP_OPS cls_rsvp6_ops 23 - #define RSVP_CLS rsvp6_classify 24 - 25 - #include "cls_rsvp.h" 26 - MODULE_LICENSE("GPL");
-203
tools/testing/selftests/tc-testing/tc-tests/filters/rsvp.json
··· 1 - [ 2 - { 3 - "id": "2141", 4 - "name": "Add rsvp filter with tcp proto and specific IP address", 5 - "category": [ 6 - "filter", 7 - "rsvp" 8 - ], 9 - "plugins": { 10 - "requires": "nsPlugin" 11 - }, 12 - "setup": [ 13 - "$TC qdisc add dev $DEV1 ingress" 14 - ], 15 - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto tcp session 198.168.10.64", 16 - "expExitCode": "0", 17 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 18 - "matchPattern": "^filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh 0x.*session 198.168.10.64 ipproto tcp", 19 - "matchCount": "1", 20 - "teardown": [ 21 - "$TC qdisc del dev $DEV1 ingress" 22 - ] 23 - }, 24 - { 25 - "id": "5267", 26 - "name": "Add rsvp filter with udp proto and specific IP address", 27 - "category": [ 28 - "filter", 29 - "rsvp" 30 - ], 31 - "plugins": { 32 - "requires": "nsPlugin" 33 - }, 34 - "setup": [ 35 - "$TC qdisc add dev $DEV1 ingress" 36 - ], 37 - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto udp session 1.1.1.1", 38 - "expExitCode": "0", 39 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 40 - "matchPattern": "^filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh 0x.*session 1.1.1.1 ipproto udp", 41 - "matchCount": "1", 42 - "teardown": [ 43 - "$TC qdisc del dev $DEV1 ingress" 44 - ] 45 - }, 46 - { 47 - "id": "2819", 48 - "name": "Add rsvp filter with src ip and src port", 49 - "category": [ 50 - "filter", 51 - "rsvp" 52 - ], 53 - "plugins": { 54 - "requires": "nsPlugin" 55 - }, 56 - "setup": [ 57 - "$TC qdisc add dev $DEV1 ingress" 58 - ], 59 - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto udp session 1.1.1.1 sender 2.2.2.2/5021 classid 1:1", 60 - "expExitCode": "0", 61 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 62 - "matchPattern": "^filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh 0x.*flowid 1:1 session 1.1.1.1 ipproto udp sender 2.2.2.2/5021", 63 - "matchCount": "1", 64 - "teardown": [ 65 - "$TC qdisc del dev $DEV1 ingress" 66 - ] 67 - }, 68 - { 69 - "id": "c967", 70 - "name": "Add rsvp filter with tunnelid and continue action", 71 - "category": [ 72 - "filter", 73 - "rsvp" 74 - ], 75 - "plugins": { 76 - "requires": "nsPlugin" 77 - }, 78 - "setup": [ 79 - "$TC qdisc add dev $DEV1 ingress" 80 - ], 81 - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto udp session 1.1.1.1 tunnelid 2 classid 1:1 action continue", 82 - "expExitCode": "0", 83 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 84 - "matchPattern": "^filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh 0x.*flowid 1:1 session 1.1.1.1 ipproto udp tunnelid 2.*action order [0-9]+: gact action continue", 85 - "matchCount": "1", 86 - "teardown": [ 87 - "$TC qdisc del dev $DEV1 ingress" 88 - ] 89 - }, 90 - { 91 - "id": "5463", 92 - "name": "Add rsvp filter with tunnel and pipe action", 93 - "category": [ 94 - "filter", 95 - "rsvp" 96 - ], 97 - "plugins": { 98 - "requires": "nsPlugin" 99 - }, 100 - "setup": [ 101 - "$TC qdisc add dev $DEV1 ingress" 102 - ], 103 - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto udp session 1.1.1.1 tunnel 2 skip 1 action pipe", 104 - "expExitCode": "0", 105 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 106 - "matchPattern": "^filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh 0x.*tunnel 2 skip 1 session 1.1.1.1 ipproto udp.*action order [0-9]+: gact action pipe", 107 - "matchCount": "1", 108 - "teardown": [ 109 - "$TC qdisc del dev $DEV1 ingress" 110 - ] 111 - }, 112 - { 113 - "id": "2332", 114 - "name": "Add rsvp filter with miltiple actions", 115 - "category": [ 116 - "filter", 117 - "rsvp" 118 - ], 119 - "plugins": { 120 - "requires": "nsPlugin" 121 - }, 122 - "setup": [ 123 - "$TC qdisc add dev $DEV1 ingress" 124 - ], 125 - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 7 rsvp ipproto udp session 1.1.1.1 classid 1:1 action skbedit mark 7 pipe action gact drop", 126 - "expExitCode": "0", 127 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 128 - "matchPattern": "^filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh 0x.*flowid 1:1 session 1.1.1.1 ipproto udp.*action order [0-9]+: skbedit mark 7 pipe.*action order [0-9]+: gact action drop", 129 - "matchCount": "1", 130 - "teardown": [ 131 - "$TC qdisc del dev $DEV1 ingress" 132 - ] 133 - }, 134 - { 135 - "id": "8879", 136 - "name": "Add rsvp filter with tunnel and skp flag", 137 - "category": [ 138 - "filter", 139 - "rsvp" 140 - ], 141 - "plugins": { 142 - "requires": "nsPlugin" 143 - }, 144 - "setup": [ 145 - "$TC qdisc add dev $DEV1 ingress" 146 - ], 147 - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto udp session 1.1.1.1 tunnel 2 skip 1 action pipe", 148 - "expExitCode": "0", 149 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 150 - "matchPattern": "^filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh 0x.*tunnel 2 skip 1 session 1.1.1.1 ipproto udp.*action order [0-9]+: gact action pipe", 151 - "matchCount": "1", 152 - "teardown": [ 153 - "$TC qdisc del dev $DEV1 ingress" 154 - ] 155 - }, 156 - { 157 - "id": "8261", 158 - "name": "List rsvp filters", 159 - "category": [ 160 - "filter", 161 - "rsvp" 162 - ], 163 - "plugins": { 164 - "requires": "nsPlugin" 165 - }, 166 - "setup": [ 167 - "$TC qdisc add dev $DEV1 ingress", 168 - "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto udp session 1.1.1.1/1234 classid 1:1", 169 - "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto tcp session 2.2.2.2/1234 classid 2:1" 170 - ], 171 - "cmdUnderTest": "$TC filter show dev $DEV1 parent ffff:", 172 - "expExitCode": "0", 173 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 174 - "matchPattern": "^filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh", 175 - "matchCount": "2", 176 - "teardown": [ 177 - "$TC qdisc del dev $DEV1 ingress" 178 - ] 179 - }, 180 - { 181 - "id": "8989", 182 - "name": "Delete rsvp filter", 183 - "category": [ 184 - "filter", 185 - "rsvp" 186 - ], 187 - "plugins": { 188 - "requires": "nsPlugin" 189 - }, 190 - "setup": [ 191 - "$TC qdisc add dev $DEV1 ingress", 192 - "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto udp session 1.1.1.1/1234 tunnelid 9 classid 2:1" 193 - ], 194 - "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: protocol ip prio 1 rsvp ipproto udp session 1.1.1.1/1234 tunnelid 9 classid 2:1", 195 - "expExitCode": "0", 196 - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 197 - "matchPattern": "filter protocol ip pref [0-9]+ rsvp chain [0-9]+ fh 0x.*flowid 2:1 session 1.1.1.1/1234 ipproto udp tunnelid 9", 198 - "matchCount": "0", 199 - "teardown": [ 200 - "$TC qdisc del dev $DEV1 ingress" 201 - ] 202 - } 203 - ]