Allow specification of per route IP tunnel instructions also for IPv6. This complements commit 3093fbe7ff4b ("route: Per route IP tunnel metadata via lightweight tunnel").
Unified · Split
| @@ -8,6 +8,7 @@ enum lwtunnel_encap_types { · 7 unmodified lines | ||
| 8 | 8 | LWTUNNEL_ENCAP_MPLS, |
| 9 | 9 | LWTUNNEL_ENCAP_IP, |
| 10 | 10 | LWTUNNEL_ENCAP_ILA, |
| 11 | + LWTUNNEL_ENCAP_IP6, | |
| 11 | 12 | __LWTUNNEL_ENCAP_MAX, |
| 12 | 13 | }; |
| 13 | 14 | |
| @@ -28,4 +29,19 @@ enum lwtunnel_ip_t { · 14 unmodified lines | ||
| 28 | 29 | |
| 29 | 30 | #define LWTUNNEL_IP_MAX (__LWTUNNEL_IP_MAX - 1) |
| 30 | 31 | |
| 32 | +enum lwtunnel_ip6_t { | |
| 33 | + LWTUNNEL_IP6_UNSPEC, | |
| 34 | + LWTUNNEL_IP6_ID, | |
| 35 | + LWTUNNEL_IP6_DST, | |
| 36 | + LWTUNNEL_IP6_SRC, | |
| 37 | + LWTUNNEL_IP6_HOPLIMIT, | |
| 38 | + LWTUNNEL_IP6_TC, | |
| 39 | + LWTUNNEL_IP6_SPORT, | |
| 40 | + LWTUNNEL_IP6_DPORT, | |
| 41 | + LWTUNNEL_IP6_FLAGS, | |
| 42 | + __LWTUNNEL_IP6_MAX, | |
| 43 | +}; | |
| 44 | + | |
| 45 | +#define LWTUNNEL_IP6_MAX (__LWTUNNEL_IP6_MAX - 1) | |
| 46 | + | |
| 31 | 47 | #endif /* _UAPI_LWTUNNEL_H_ */ |
| @@ -299,9 +299,111 @@ static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { · 298 unmodified lines | ||
| 299 | 299 | .cmp_encap = ip_tun_cmp_encap, |
| 300 | 300 | }; |
| 301 | 301 | |
| 302 | +static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = { | |
| 303 | + [LWTUNNEL_IP6_ID] = { .type = NLA_U64 }, | |
| 304 | + [LWTUNNEL_IP6_DST] = { .len = sizeof(struct in6_addr) }, | |
| 305 | + [LWTUNNEL_IP6_SRC] = { .len = sizeof(struct in6_addr) }, | |
| 306 | + [LWTUNNEL_IP6_HOPLIMIT] = { .type = NLA_U8 }, | |
| 307 | + [LWTUNNEL_IP6_TC] = { .type = NLA_U8 }, | |
| 308 | + [LWTUNNEL_IP6_SPORT] = { .type = NLA_U16 }, | |
| 309 | + [LWTUNNEL_IP6_DPORT] = { .type = NLA_U16 }, | |
| 310 | + [LWTUNNEL_IP6_FLAGS] = { .type = NLA_U16 }, | |
| 311 | +}; | |
| 312 | + | |
| 313 | +static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr, | |
| 314 | + struct lwtunnel_state **ts) | |
| 315 | +{ | |
| 316 | + struct ip_tunnel_info *tun_info; | |
| 317 | + struct lwtunnel_state *new_state; | |
| 318 | + struct nlattr *tb[LWTUNNEL_IP6_MAX + 1]; | |
| 319 | + int err; | |
| 320 | + | |
| 321 | + err = nla_parse_nested(tb, LWTUNNEL_IP6_MAX, attr, ip6_tun_policy); | |
| 322 | + if (err < 0) | |
| 323 | + return err; | |
| 324 | + | |
| 325 | + new_state = lwtunnel_state_alloc(sizeof(*tun_info)); | |
| 326 | + if (!new_state) | |
| 327 | + return -ENOMEM; | |
| 328 | + | |
| 329 | + new_state->type = LWTUNNEL_ENCAP_IP6; | |
| 330 | + | |
| 331 | + tun_info = lwt_tun_info(new_state); | |
| 332 | + | |
| 333 | + if (tb[LWTUNNEL_IP6_ID]) | |
| 334 | + tun_info->key.tun_id = nla_get_u64(tb[LWTUNNEL_IP6_ID]); | |
| 335 | + | |
| 336 | + if (tb[LWTUNNEL_IP6_DST]) | |
| 337 | + tun_info->key.u.ipv6.dst = nla_get_in6_addr(tb[LWTUNNEL_IP6_DST]); | |
| 338 | + | |
| 339 | + if (tb[LWTUNNEL_IP6_SRC]) | |
| 340 | + tun_info->key.u.ipv6.src = nla_get_in6_addr(tb[LWTUNNEL_IP6_SRC]); | |
| 341 | + | |
| 342 | + if (tb[LWTUNNEL_IP6_HOPLIMIT]) | |
| 343 | + tun_info->key.ttl = nla_get_u8(tb[LWTUNNEL_IP6_HOPLIMIT]); | |
| 344 | + | |
| 345 | + if (tb[LWTUNNEL_IP6_TC]) | |
| 346 | + tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP6_TC]); | |
| 347 | + | |
| 348 | + if (tb[LWTUNNEL_IP6_SPORT]) | |
| 349 | + tun_info->key.tp_src = nla_get_be16(tb[LWTUNNEL_IP6_SPORT]); | |
| 350 | + | |
| 351 | + if (tb[LWTUNNEL_IP6_DPORT]) | |
| 352 | + tun_info->key.tp_dst = nla_get_be16(tb[LWTUNNEL_IP6_DPORT]); | |
| 353 | + | |
| 354 | + if (tb[LWTUNNEL_IP6_FLAGS]) | |
| 355 | + tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]); | |
| 356 | + | |
| 357 | + tun_info->mode = IP_TUNNEL_INFO_TX; | |
| 358 | + tun_info->options = NULL; | |
| 359 | + tun_info->options_len = 0; | |
| 360 | + | |
| 361 | + *ts = new_state; | |
| 362 | + | |
| 363 | + return 0; | |
| 364 | +} | |
| 365 | + | |
| 366 | +static int ip6_tun_fill_encap_info(struct sk_buff *skb, | |
| 367 | + struct lwtunnel_state *lwtstate) | |
| 368 | +{ | |
| 369 | + struct ip_tunnel_info *tun_info = lwt_tun_info(lwtstate); | |
| 370 | + | |
| 371 | + if (nla_put_u64(skb, LWTUNNEL_IP6_ID, tun_info->key.tun_id) || | |
| 372 | + nla_put_in6_addr(skb, LWTUNNEL_IP6_DST, &tun_info->key.u.ipv6.dst) || | |
| 373 | + nla_put_in6_addr(skb, LWTUNNEL_IP6_SRC, &tun_info->key.u.ipv6.src) || | |
| 374 | + nla_put_u8(skb, LWTUNNEL_IP6_HOPLIMIT, tun_info->key.tos) || | |
| 375 | + nla_put_u8(skb, LWTUNNEL_IP6_TC, tun_info->key.ttl) || | |
| 376 | + nla_put_u16(skb, LWTUNNEL_IP6_SPORT, tun_info->key.tp_src) || | |
| 377 | + nla_put_u16(skb, LWTUNNEL_IP6_DPORT, tun_info->key.tp_dst) || | |
| 378 | + nla_put_u16(skb, LWTUNNEL_IP6_FLAGS, tun_info->key.tun_flags)) | |
| 379 | + return -ENOMEM; | |
| 380 | + | |
| 381 | + return 0; | |
| 382 | +} | |
| 383 | + | |
| 384 | +static int ip6_tun_encap_nlsize(struct lwtunnel_state *lwtstate) | |
| 385 | +{ | |
| 386 | + return nla_total_size(8) /* LWTUNNEL_IP6_ID */ | |
| 387 | + + nla_total_size(16) /* LWTUNNEL_IP6_DST */ | |
| 388 | + + nla_total_size(16) /* LWTUNNEL_IP6_SRC */ | |
| 389 | + + nla_total_size(1) /* LWTUNNEL_IP6_HOPLIMIT */ | |
| 390 | + + nla_total_size(1) /* LWTUNNEL_IP6_TC */ | |
| 391 | + + nla_total_size(2) /* LWTUNNEL_IP6_SPORT */ | |
| 392 | + + nla_total_size(2) /* LWTUNNEL_IP6_DPORT */ | |
| 393 | + + nla_total_size(2); /* LWTUNNEL_IP6_FLAGS */ | |
| 394 | +} | |
| 395 | + | |
| 396 | +static const struct lwtunnel_encap_ops ip6_tun_lwt_ops = { | |
| 397 | + .build_state = ip6_tun_build_state, | |
| 398 | + .fill_encap = ip6_tun_fill_encap_info, | |
| 399 | + .get_encap_size = ip6_tun_encap_nlsize, | |
| 400 | + .cmp_encap = ip_tun_cmp_encap, | |
| 401 | +}; | |
| 402 | + | |
| 302 | 403 | void __init ip_tunnel_core_init(void) |
| 303 | 404 | { |
| 304 | 405 | lwtunnel_encap_add_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); |
| 406 | + lwtunnel_encap_add_ops(&ip6_tun_lwt_ops, LWTUNNEL_ENCAP_IP6); | |
| 305 | 407 | } |
| 306 | 408 | |
| 307 | 409 | struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE; |