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 | LWTUNNEL_ENCAP_MPLS, | 8 | LWTUNNEL_ENCAP_MPLS, |
| 9 | LWTUNNEL_ENCAP_IP, | 9 | LWTUNNEL_ENCAP_IP, |
| 10 | LWTUNNEL_ENCAP_ILA, | 10 | LWTUNNEL_ENCAP_ILA, |
| 11 | LWTUNNEL_ENCAP_IP6, | ||
| 11 | __LWTUNNEL_ENCAP_MAX, | 12 | __LWTUNNEL_ENCAP_MAX, |
| 12 | }; | 13 | }; |
| 13 | 14 | ||
| @@ -28,4 +29,19 @@ enum lwtunnel_ip_t { · 14 unmodified lines | |||
| 28 | 29 | ||
| 29 | #define LWTUNNEL_IP_MAX (__LWTUNNEL_IP_MAX - 1) | 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 | #endif /* _UAPI_LWTUNNEL_H_ */ | 47 | #endif /* _UAPI_LWTUNNEL_H_ */ |
| @@ -299,9 +299,111 @@ static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { · 298 unmodified lines | |||
| 299 | .cmp_encap = ip_tun_cmp_encap, | 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 | void __init ip_tunnel_core_init(void) | 403 | void __init ip_tunnel_core_init(void) |
| 303 | { | 404 | { |
| 304 | lwtunnel_encap_add_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); | 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 | struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE; | 409 | struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE; |