This patch provides a new feature (i.e., "tunsrc") for the tunnel (i.e., "encap") mode of ioam6. Just like seg6 already does, except it is attached to a route. The "tunsrc" is optional: when not provided (by default), the automatic resolution is applied. Using "tunsrc" when possible has a benefit: performance. See the comparison: - before (= "encap" mode): https://ibb.co/bNCzvf7 - after (= "encap" mode with "tunsrc"): https://ibb.co/PT8L6yq
Unified · Split
| @@ -50,6 +50,12 @@ enum { · 49 unmodified lines | |||
| 50 | IOAM6_IPTUNNEL_FREQ_K, /* u32 */ | 50 | IOAM6_IPTUNNEL_FREQ_K, /* u32 */ |
| 51 | IOAM6_IPTUNNEL_FREQ_N, /* u32 */ | 51 | IOAM6_IPTUNNEL_FREQ_N, /* u32 */ |
| 52 | 52 | ||
| 53 | /* Tunnel src address. | ||
| 54 | * For encap,auto modes. | ||
| 55 | * Optional (automatic if not provided). | ||
| 56 | */ | ||
| 57 | IOAM6_IPTUNNEL_SRC, /* struct in6_addr */ | ||
| 58 | |||
| 53 | __IOAM6_IPTUNNEL_MAX, | 59 | __IOAM6_IPTUNNEL_MAX, |
| 54 | }; | 60 | }; |
| 55 | 61 | ||
| @@ -42,6 +42,8 @@ struct ioam6_lwt { · 41 unmodified lines | |||
| 42 | struct ioam6_lwt_freq freq; | 42 | struct ioam6_lwt_freq freq; |
| 43 | atomic_t pkt_cnt; | 43 | atomic_t pkt_cnt; |
| 44 | u8 mode; | 44 | u8 mode; |
| 45 | bool has_tunsrc; | ||
| 46 | struct in6_addr tunsrc; | ||
| 45 | struct in6_addr tundst; | 47 | struct in6_addr tundst; |
| 46 | struct ioam6_lwt_encap tuninfo; | 48 | struct ioam6_lwt_encap tuninfo; |
| 47 | }; | 49 | }; |
| @@ -72,6 +74,7 @@ static const struct nla_policy ioam6_iptunnel_policy[IOAM6_IPTUNNEL_MAX + 1] = { · 24 unmodified lines | |||
| 72 | [IOAM6_IPTUNNEL_MODE] = NLA_POLICY_RANGE(NLA_U8, | 74 | [IOAM6_IPTUNNEL_MODE] = NLA_POLICY_RANGE(NLA_U8, |
| 73 | IOAM6_IPTUNNEL_MODE_MIN, | 75 | IOAM6_IPTUNNEL_MODE_MIN, |
| 74 | IOAM6_IPTUNNEL_MODE_MAX), | 76 | IOAM6_IPTUNNEL_MODE_MAX), |
| 77 | [IOAM6_IPTUNNEL_SRC] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), | ||
| 75 | [IOAM6_IPTUNNEL_DST] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), | 78 | [IOAM6_IPTUNNEL_DST] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), |
| 76 | [IOAM6_IPTUNNEL_TRACE] = NLA_POLICY_EXACT_LEN( | 79 | [IOAM6_IPTUNNEL_TRACE] = NLA_POLICY_EXACT_LEN( |
| 77 | sizeof(struct ioam6_trace_hdr)), | 80 | sizeof(struct ioam6_trace_hdr)), |
| @@ -144,6 +147,11 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla, · 66 unmodified lines | |||
| 144 | else | 147 | else |
| 145 | mode = nla_get_u8(tb[IOAM6_IPTUNNEL_MODE]); | 148 | mode = nla_get_u8(tb[IOAM6_IPTUNNEL_MODE]); |
| 146 | 149 | ||
| 150 | if (tb[IOAM6_IPTUNNEL_SRC] && mode == IOAM6_IPTUNNEL_MODE_INLINE) { | ||
| 151 | NL_SET_ERR_MSG(extack, "no tunnel src expected with this mode"); | ||
| 152 | return -EINVAL; | ||
| 153 | } | ||
| 154 | |||
| 147 | if (!tb[IOAM6_IPTUNNEL_DST] && mode != IOAM6_IPTUNNEL_MODE_INLINE) { | 155 | if (!tb[IOAM6_IPTUNNEL_DST] && mode != IOAM6_IPTUNNEL_MODE_INLINE) { |
| 148 | NL_SET_ERR_MSG(extack, "this mode needs a tunnel destination"); | 156 | NL_SET_ERR_MSG(extack, "this mode needs a tunnel destination"); |
| 149 | return -EINVAL; | 157 | return -EINVAL; |
| @@ -168,16 +176,29 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla, · 18 unmodified lines | |||
| 168 | 176 | ||
| 169 | ilwt = ioam6_lwt_state(lwt); | 177 | ilwt = ioam6_lwt_state(lwt); |
| 170 | err = dst_cache_init(&ilwt->cache, GFP_ATOMIC); | 178 | err = dst_cache_init(&ilwt->cache, GFP_ATOMIC); |
| 171 | if (err) { | 179 | if (err) |
| 172 | kfree(lwt); | 180 | goto free_lwt; |
| 173 | return err; | ||
| 174 | } | ||
| 175 | 181 | ||
| 176 | atomic_set(&ilwt->pkt_cnt, 0); | 182 | atomic_set(&ilwt->pkt_cnt, 0); |
| 177 | ilwt->freq.k = freq_k; | 183 | ilwt->freq.k = freq_k; |
| 178 | ilwt->freq.n = freq_n; | 184 | ilwt->freq.n = freq_n; |
| 179 | 185 | ||
| 180 | ilwt->mode = mode; | 186 | ilwt->mode = mode; |
| 187 | |||
| 188 | if (!tb[IOAM6_IPTUNNEL_SRC]) { | ||
| 189 | ilwt->has_tunsrc = false; | ||
| 190 | } else { | ||
| 191 | ilwt->has_tunsrc = true; | ||
| 192 | ilwt->tunsrc = nla_get_in6_addr(tb[IOAM6_IPTUNNEL_SRC]); | ||
| 193 | |||
| 194 | if (ipv6_addr_any(&ilwt->tunsrc)) { | ||
| 195 | NL_SET_ERR_MSG_ATTR(extack, tb[IOAM6_IPTUNNEL_SRC], | ||
| 196 | "invalid tunnel source address"); | ||
| 197 | err = -EINVAL; | ||
| 198 | goto free_cache; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 181 | if (tb[IOAM6_IPTUNNEL_DST]) | 202 | if (tb[IOAM6_IPTUNNEL_DST]) |
| 182 | ilwt->tundst = nla_get_in6_addr(tb[IOAM6_IPTUNNEL_DST]); | 203 | ilwt->tundst = nla_get_in6_addr(tb[IOAM6_IPTUNNEL_DST]); |
| 183 | 204 | ||
| @@ -202,6 +223,11 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla, · 18 unmodified lines | |||
| 202 | *ts = lwt; | 223 | *ts = lwt; |
| 203 | 224 | ||
| 204 | return 0; | 225 | return 0; |
| 226 | free_cache: | ||
| 227 | dst_cache_destroy(&ilwt->cache); | ||
| 228 | free_lwt: | ||
| 229 | kfree(lwt); | ||
| 230 | return err; | ||
| 205 | } | 231 | } |
| 206 | 232 | ||
| 207 | static int ioam6_do_fill(struct net *net, struct sk_buff *skb) | 233 | static int ioam6_do_fill(struct net *net, struct sk_buff *skb) |
| @@ -257,6 +283,8 @@ static int ioam6_do_inline(struct net *net, struct sk_buff *skb, · 49 unmodified lines | |||
| 257 | 283 | ||
| 258 | static int ioam6_do_encap(struct net *net, struct sk_buff *skb, | 284 | static int ioam6_do_encap(struct net *net, struct sk_buff *skb, |
| 259 | struct ioam6_lwt_encap *tuninfo, | 285 | struct ioam6_lwt_encap *tuninfo, |
| 286 | bool has_tunsrc, | ||
| 287 | struct in6_addr *tunsrc, | ||
| 260 | struct in6_addr *tundst) | 288 | struct in6_addr *tundst) |
| 261 | { | 289 | { |
| 262 | struct dst_entry *dst = skb_dst(skb); | 290 | struct dst_entry *dst = skb_dst(skb); |
| @@ -286,8 +314,12 @@ static int ioam6_do_encap(struct net *net, struct sk_buff *skb, · 23 unmodified lines | |||
| 286 | hdr->nexthdr = NEXTHDR_HOP; | 314 | hdr->nexthdr = NEXTHDR_HOP; |
| 287 | hdr->payload_len = cpu_to_be16(skb->len - sizeof(*hdr)); | 315 | hdr->payload_len = cpu_to_be16(skb->len - sizeof(*hdr)); |
| 288 | hdr->daddr = *tundst; | 316 | hdr->daddr = *tundst; |
| 289 | ipv6_dev_get_saddr(net, dst->dev, &hdr->daddr, | 317 | |
| 290 | IPV6_PREFER_SRC_PUBLIC, &hdr->saddr); | 318 | if (has_tunsrc) |
| 319 | memcpy(&hdr->saddr, tunsrc, sizeof(*tunsrc)); | ||
| 320 | else | ||
| 321 | ipv6_dev_get_saddr(net, dst->dev, &hdr->daddr, | ||
| 322 | IPV6_PREFER_SRC_PUBLIC, &hdr->saddr); | ||
| 291 | 323 | ||
| 292 | skb_postpush_rcsum(skb, hdr, len); | 324 | skb_postpush_rcsum(skb, hdr, len); |
| 293 | 325 | ||
| @@ -329,7 +361,9 @@ do_inline: · 35 unmodified lines | |||
| 329 | case IOAM6_IPTUNNEL_MODE_ENCAP: | 361 | case IOAM6_IPTUNNEL_MODE_ENCAP: |
| 330 | do_encap: | 362 | do_encap: |
| 331 | /* Encapsulation (ip6ip6) */ | 363 | /* Encapsulation (ip6ip6) */ |
| 332 | err = ioam6_do_encap(net, skb, &ilwt->tuninfo, &ilwt->tundst); | 364 | err = ioam6_do_encap(net, skb, &ilwt->tuninfo, |
| 365 | ilwt->has_tunsrc, &ilwt->tunsrc, | ||
| 366 | &ilwt->tundst); | ||
| 333 | if (unlikely(err)) | 367 | if (unlikely(err)) |
| 334 | goto drop; | 368 | goto drop; |
| 335 | 369 | ||
| @@ -415,6 +449,13 @@ static int ioam6_fill_encap_info(struct sk_buff *skb, · 79 unmodified lines | |||
| 415 | goto ret; | 449 | goto ret; |
| 416 | 450 | ||
| 417 | if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE) { | 451 | if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE) { |
| 452 | if (ilwt->has_tunsrc) { | ||
| 453 | err = nla_put_in6_addr(skb, IOAM6_IPTUNNEL_SRC, | ||
| 454 | &ilwt->tunsrc); | ||
| 455 | if (err) | ||
| 456 | goto ret; | ||
| 457 | } | ||
| 458 | |||
| 418 | err = nla_put_in6_addr(skb, IOAM6_IPTUNNEL_DST, &ilwt->tundst); | 459 | err = nla_put_in6_addr(skb, IOAM6_IPTUNNEL_DST, &ilwt->tundst); |
| 419 | if (err) | 460 | if (err) |
| 420 | goto ret; | 461 | goto ret; |
| @@ -436,8 +477,12 @@ static int ioam6_encap_nlsize(struct lwtunnel_state *lwtstate) · 15 unmodified lines | |||
| 436 | nla_total_size(sizeof(ilwt->mode)) + | 477 | nla_total_size(sizeof(ilwt->mode)) + |
| 437 | nla_total_size(sizeof(ilwt->tuninfo.traceh)); | 478 | nla_total_size(sizeof(ilwt->tuninfo.traceh)); |
| 438 | 479 | ||
| 439 | if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE) | 480 | if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE) { |
| 481 | if (ilwt->has_tunsrc) | ||
| 482 | nlsize += nla_total_size(sizeof(ilwt->tunsrc)); | ||
| 483 | |||
| 440 | nlsize += nla_total_size(sizeof(ilwt->tundst)); | 484 | nlsize += nla_total_size(sizeof(ilwt->tundst)); |
| 485 | } | ||
| 441 | 486 | ||
| 442 | return nlsize; | 487 | return nlsize; |
| 443 | } | 488 | } |
| @@ -452,8 +497,12 @@ static int ioam6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) · 8 unmodified lines | |||
| 452 | return (ilwt_a->freq.k != ilwt_b->freq.k || | 497 | return (ilwt_a->freq.k != ilwt_b->freq.k || |
| 453 | ilwt_a->freq.n != ilwt_b->freq.n || | 498 | ilwt_a->freq.n != ilwt_b->freq.n || |
| 454 | ilwt_a->mode != ilwt_b->mode || | 499 | ilwt_a->mode != ilwt_b->mode || |
| 500 | ilwt_a->has_tunsrc != ilwt_b->has_tunsrc || | ||
| 455 | (ilwt_a->mode != IOAM6_IPTUNNEL_MODE_INLINE && | 501 | (ilwt_a->mode != IOAM6_IPTUNNEL_MODE_INLINE && |
| 456 | !ipv6_addr_equal(&ilwt_a->tundst, &ilwt_b->tundst)) || | 502 | !ipv6_addr_equal(&ilwt_a->tundst, &ilwt_b->tundst)) || |
| 503 | (ilwt_a->mode != IOAM6_IPTUNNEL_MODE_INLINE && | ||
| 504 | ilwt_a->has_tunsrc && | ||
| 505 | !ipv6_addr_equal(&ilwt_a->tunsrc, &ilwt_b->tunsrc)) || | ||
| 457 | trace_a->namespace_id != trace_b->namespace_id); | 506 | trace_a->namespace_id != trace_b->namespace_id); |
| 458 | } | 507 | } |
| 459 | 508 | ||