|
43 | 43 | #include "flow.h" |
44 | 44 | #include "conntrack.h" |
45 | 45 | #include "vport.h" |
| 46 | +#include "flow_netlink.h" |
46 | 47 |
|
47 | 48 | struct deferred_action { |
48 | 49 | struct sk_buff *skb; |
@@ -380,6 +381,38 @@ static int push_eth(struct sk_buff *skb, struct sw_flow_key *key, |
380 | 381 | return 0; |
381 | 382 | } |
382 | 383 |
|
| 384 | +static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key, |
| 385 | + const struct nshhdr *nh) |
| 386 | +{ |
| 387 | + int err; |
| 388 | + |
| 389 | + err = nsh_push(skb, nh); |
| 390 | + if (err) |
| 391 | + return err; |
| 392 | + |
| 393 | + /* safe right before invalidate_flow_key */ |
| 394 | + key->mac_proto = MAC_PROTO_NONE; |
| 395 | + invalidate_flow_key(key); |
| 396 | + return 0; |
| 397 | +} |
| 398 | + |
| 399 | +static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key) |
| 400 | +{ |
| 401 | + int err; |
| 402 | + |
| 403 | + err = nsh_pop(skb); |
| 404 | + if (err) |
| 405 | + return err; |
| 406 | + |
| 407 | + /* safe right before invalidate_flow_key */ |
| 408 | + if (skb->protocol == htons(ETH_P_TEB)) |
| 409 | + key->mac_proto = MAC_PROTO_ETHERNET; |
| 410 | + else |
| 411 | + key->mac_proto = MAC_PROTO_NONE; |
| 412 | + invalidate_flow_key(key); |
| 413 | + return 0; |
| 414 | +} |
| 415 | + |
383 | 416 | static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh, |
384 | 417 | __be32 addr, __be32 new_addr) |
385 | 418 | { |
@@ -602,6 +635,69 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key, |
602 | 635 | return 0; |
603 | 636 | } |
604 | 637 |
|
| 638 | +static int set_nsh(struct sk_buff *skb, struct sw_flow_key *flow_key, |
| 639 | + const struct nlattr *a) |
| 640 | +{ |
| 641 | + struct nshhdr *nh; |
| 642 | + size_t length; |
| 643 | + int err; |
| 644 | + u8 flags; |
| 645 | + u8 ttl; |
| 646 | + int i; |
| 647 | + |
| 648 | + struct ovs_key_nsh key; |
| 649 | + struct ovs_key_nsh mask; |
| 650 | + |
| 651 | + err = nsh_key_from_nlattr(a, &key, &mask); |
| 652 | + if (err) |
| 653 | + return err; |
| 654 | + |
| 655 | + /* Make sure the NSH base header is there */ |
| 656 | + if (!pskb_may_pull(skb, skb_network_offset(skb) + NSH_BASE_HDR_LEN)) |
| 657 | + return -ENOMEM; |
| 658 | + |
| 659 | + nh = nsh_hdr(skb); |
| 660 | + length = nsh_hdr_len(nh); |
| 661 | + |
| 662 | + /* Make sure the whole NSH header is there */ |
| 663 | + err = skb_ensure_writable(skb, skb_network_offset(skb) + |
| 664 | + length); |
| 665 | + if (unlikely(err)) |
| 666 | + return err; |
| 667 | + |
| 668 | + nh = nsh_hdr(skb); |
| 669 | + skb_postpull_rcsum(skb, nh, length); |
| 670 | + flags = nsh_get_flags(nh); |
| 671 | + flags = OVS_MASKED(flags, key.base.flags, mask.base.flags); |
| 672 | + flow_key->nsh.base.flags = flags; |
| 673 | + ttl = nsh_get_ttl(nh); |
| 674 | + ttl = OVS_MASKED(ttl, key.base.ttl, mask.base.ttl); |
| 675 | + flow_key->nsh.base.ttl = ttl; |
| 676 | + nsh_set_flags_and_ttl(nh, flags, ttl); |
| 677 | + nh->path_hdr = OVS_MASKED(nh->path_hdr, key.base.path_hdr, |
| 678 | + mask.base.path_hdr); |
| 679 | + flow_key->nsh.base.path_hdr = nh->path_hdr; |
| 680 | + switch (nh->mdtype) { |
| 681 | + case NSH_M_TYPE1: |
| 682 | + for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++) { |
| 683 | + nh->md1.context[i] = |
| 684 | + OVS_MASKED(nh->md1.context[i], key.context[i], |
| 685 | + mask.context[i]); |
| 686 | + } |
| 687 | + memcpy(flow_key->nsh.context, nh->md1.context, |
| 688 | + sizeof(nh->md1.context)); |
| 689 | + break; |
| 690 | + case NSH_M_TYPE2: |
| 691 | + memset(flow_key->nsh.context, 0, |
| 692 | + sizeof(flow_key->nsh.context)); |
| 693 | + break; |
| 694 | + default: |
| 695 | + return -EINVAL; |
| 696 | + } |
| 697 | + skb_postpush_rcsum(skb, nh, length); |
| 698 | + return 0; |
| 699 | +} |
| 700 | + |
605 | 701 | /* Must follow skb_ensure_writable() since that can move the skb data. */ |
606 | 702 | static void set_tp_port(struct sk_buff *skb, __be16 *port, |
607 | 703 | __be16 new_port, __sum16 *check) |
@@ -1024,6 +1120,10 @@ static int execute_masked_set_action(struct sk_buff *skb, |
1024 | 1120 | get_mask(a, struct ovs_key_ethernet *)); |
1025 | 1121 | break; |
1026 | 1122 |
|
| 1123 | + case OVS_KEY_ATTR_NSH: |
| 1124 | + err = set_nsh(skb, flow_key, a); |
| 1125 | + break; |
| 1126 | + |
1027 | 1127 | case OVS_KEY_ATTR_IPV4: |
1028 | 1128 | err = set_ipv4(skb, flow_key, nla_data(a), |
1029 | 1129 | get_mask(a, struct ovs_key_ipv4 *)); |
@@ -1214,6 +1314,22 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, |
1214 | 1314 | case OVS_ACTION_ATTR_POP_ETH: |
1215 | 1315 | err = pop_eth(skb, key); |
1216 | 1316 | break; |
| 1317 | + |
| 1318 | + case OVS_ACTION_ATTR_PUSH_NSH: { |
| 1319 | + u8 buffer[NSH_HDR_MAX_LEN]; |
| 1320 | + struct nshhdr *nh = (struct nshhdr *)buffer; |
| 1321 | + |
| 1322 | + err = nsh_hdr_from_nlattr(nla_data(a), nh, |
| 1323 | + NSH_HDR_MAX_LEN); |
| 1324 | + if (unlikely(err)) |
| 1325 | + break; |
| 1326 | + err = push_nsh(skb, key, nh); |
| 1327 | + break; |
| 1328 | + } |
| 1329 | + |
| 1330 | + case OVS_ACTION_ATTR_POP_NSH: |
| 1331 | + err = pop_nsh(skb, key); |
| 1332 | + break; |
1217 | 1333 | } |
1218 | 1334 |
|
1219 | 1335 | if (unlikely(err)) { |
|
0 commit comments