|
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