diff options
| -rw-r--r-- | net/mpls/af_mpls.c | 71 |
1 files changed, 44 insertions, 27 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 04306989d054..8c5707db53c5 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c | |||
| @@ -27,11 +27,23 @@ | |||
| 27 | /* This maximum ha length copied from the definition of struct neighbour */ | 27 | /* This maximum ha length copied from the definition of struct neighbour */ |
| 28 | #define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))) | 28 | #define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))) |
| 29 | 29 | ||
| 30 | enum mpls_payload_type { | ||
| 31 | MPT_UNSPEC, /* IPv4 or IPv6 */ | ||
| 32 | MPT_IPV4 = 4, | ||
| 33 | MPT_IPV6 = 6, | ||
| 34 | |||
| 35 | /* Other types not implemented: | ||
| 36 | * - Pseudo-wire with or without control word (RFC4385) | ||
| 37 | * - GAL (RFC5586) | ||
| 38 | */ | ||
| 39 | }; | ||
| 40 | |||
| 30 | struct mpls_route { /* next hop label forwarding entry */ | 41 | struct mpls_route { /* next hop label forwarding entry */ |
| 31 | struct net_device __rcu *rt_dev; | 42 | struct net_device __rcu *rt_dev; |
| 32 | struct rcu_head rt_rcu; | 43 | struct rcu_head rt_rcu; |
| 33 | u32 rt_label[MAX_NEW_LABELS]; | 44 | u32 rt_label[MAX_NEW_LABELS]; |
| 34 | u8 rt_protocol; /* routing protocol that set this entry */ | 45 | u8 rt_protocol; /* routing protocol that set this entry */ |
| 46 | u8 rt_payload_type; | ||
| 35 | u8 rt_labels; | 47 | u8 rt_labels; |
| 36 | u8 rt_via_alen; | 48 | u8 rt_via_alen; |
| 37 | u8 rt_via_table; | 49 | u8 rt_via_table; |
| @@ -96,16 +108,8 @@ EXPORT_SYMBOL_GPL(mpls_pkt_too_big); | |||
| 96 | static bool mpls_egress(struct mpls_route *rt, struct sk_buff *skb, | 108 | static bool mpls_egress(struct mpls_route *rt, struct sk_buff *skb, |
| 97 | struct mpls_entry_decoded dec) | 109 | struct mpls_entry_decoded dec) |
| 98 | { | 110 | { |
| 99 | /* RFC4385 and RFC5586 encode other packets in mpls such that | 111 | enum mpls_payload_type payload_type; |
| 100 | * they don't conflict with the ip version number, making | 112 | bool success = false; |
| 101 | * decoding by examining the ip version correct in everything | ||
| 102 | * except for the strangest cases. | ||
| 103 | * | ||
| 104 | * The strange cases if we choose to support them will require | ||
| 105 | * manual configuration. | ||
| 106 | */ | ||
| 107 | struct iphdr *hdr4; | ||
| 108 | bool success = true; | ||
| 109 | 113 | ||
| 110 | /* The IPv4 code below accesses through the IPv4 header | 114 | /* The IPv4 code below accesses through the IPv4 header |
| 111 | * checksum, which is 12 bytes into the packet. | 115 | * checksum, which is 12 bytes into the packet. |
| @@ -120,23 +124,32 @@ static bool mpls_egress(struct mpls_route *rt, struct sk_buff *skb, | |||
| 120 | if (!pskb_may_pull(skb, 12)) | 124 | if (!pskb_may_pull(skb, 12)) |
| 121 | return false; | 125 | return false; |
| 122 | 126 | ||
| 123 | /* Use ip_hdr to find the ip protocol version */ | 127 | payload_type = rt->rt_payload_type; |
| 124 | hdr4 = ip_hdr(skb); | 128 | if (payload_type == MPT_UNSPEC) |
| 125 | if (hdr4->version == 4) { | 129 | payload_type = ip_hdr(skb)->version; |
| 130 | |||
| 131 | switch (payload_type) { | ||
| 132 | case MPT_IPV4: { | ||
| 133 | struct iphdr *hdr4 = ip_hdr(skb); | ||
| 126 | skb->protocol = htons(ETH_P_IP); | 134 | skb->protocol = htons(ETH_P_IP); |
| 127 | csum_replace2(&hdr4->check, | 135 | csum_replace2(&hdr4->check, |
| 128 | htons(hdr4->ttl << 8), | 136 | htons(hdr4->ttl << 8), |
| 129 | htons(dec.ttl << 8)); | 137 | htons(dec.ttl << 8)); |
| 130 | hdr4->ttl = dec.ttl; | 138 | hdr4->ttl = dec.ttl; |
| 139 | success = true; | ||
| 140 | break; | ||
| 131 | } | 141 | } |
| 132 | else if (hdr4->version == 6) { | 142 | case MPT_IPV6: { |
| 133 | struct ipv6hdr *hdr6 = ipv6_hdr(skb); | 143 | struct ipv6hdr *hdr6 = ipv6_hdr(skb); |
| 134 | skb->protocol = htons(ETH_P_IPV6); | 144 | skb->protocol = htons(ETH_P_IPV6); |
| 135 | hdr6->hop_limit = dec.ttl; | 145 | hdr6->hop_limit = dec.ttl; |
| 146 | success = true; | ||
| 147 | break; | ||
| 136 | } | 148 | } |
| 137 | else | 149 | case MPT_UNSPEC: |
| 138 | /* version 0 and version 1 are used by pseudo wires */ | 150 | break; |
| 139 | success = false; | 151 | } |
| 152 | |||
| 140 | return success; | 153 | return success; |
| 141 | } | 154 | } |
| 142 | 155 | ||
| @@ -255,16 +268,17 @@ static const struct nla_policy rtm_mpls_policy[RTA_MAX+1] = { | |||
| 255 | }; | 268 | }; |
| 256 | 269 | ||
| 257 | struct mpls_route_config { | 270 | struct mpls_route_config { |
| 258 | u32 rc_protocol; | 271 | u32 rc_protocol; |
| 259 | u32 rc_ifindex; | 272 | u32 rc_ifindex; |
| 260 | u16 rc_via_table; | 273 | u16 rc_via_table; |
| 261 | u16 rc_via_alen; | 274 | u16 rc_via_alen; |
| 262 | u8 rc_via[MAX_VIA_ALEN]; | 275 | u8 rc_via[MAX_VIA_ALEN]; |
| 263 | u32 rc_label; | 276 | u32 rc_label; |
| 264 | u32 rc_output_labels; | 277 | u32 rc_output_labels; |
| 265 | u32 rc_output_label[MAX_NEW_LABELS]; | 278 | u32 rc_output_label[MAX_NEW_LABELS]; |
| 266 | u32 rc_nlflags; | 279 | u32 rc_nlflags; |
| 267 | struct nl_info rc_nlinfo; | 280 | enum mpls_payload_type rc_payload_type; |
| 281 | struct nl_info rc_nlinfo; | ||
| 268 | }; | 282 | }; |
| 269 | 283 | ||
| 270 | static struct mpls_route *mpls_rt_alloc(size_t alen) | 284 | static struct mpls_route *mpls_rt_alloc(size_t alen) |
| @@ -493,6 +507,7 @@ static int mpls_route_add(struct mpls_route_config *cfg) | |||
| 493 | rt->rt_label[i] = cfg->rc_output_label[i]; | 507 | rt->rt_label[i] = cfg->rc_output_label[i]; |
| 494 | rt->rt_protocol = cfg->rc_protocol; | 508 | rt->rt_protocol = cfg->rc_protocol; |
| 495 | RCU_INIT_POINTER(rt->rt_dev, dev); | 509 | RCU_INIT_POINTER(rt->rt_dev, dev); |
| 510 | rt->rt_payload_type = cfg->rc_payload_type; | ||
| 496 | rt->rt_via_table = cfg->rc_via_table; | 511 | rt->rt_via_table = cfg->rc_via_table; |
| 497 | memcpy(rt->rt_via, cfg->rc_via, cfg->rc_via_alen); | 512 | memcpy(rt->rt_via, cfg->rc_via, cfg->rc_via_alen); |
| 498 | 513 | ||
| @@ -1047,6 +1062,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) | |||
| 1047 | goto nort0; | 1062 | goto nort0; |
| 1048 | RCU_INIT_POINTER(rt0->rt_dev, lo); | 1063 | RCU_INIT_POINTER(rt0->rt_dev, lo); |
| 1049 | rt0->rt_protocol = RTPROT_KERNEL; | 1064 | rt0->rt_protocol = RTPROT_KERNEL; |
| 1065 | rt0->rt_payload_type = MPT_IPV4; | ||
| 1050 | rt0->rt_via_table = NEIGH_LINK_TABLE; | 1066 | rt0->rt_via_table = NEIGH_LINK_TABLE; |
| 1051 | memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); | 1067 | memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); |
| 1052 | } | 1068 | } |
| @@ -1057,6 +1073,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) | |||
| 1057 | goto nort2; | 1073 | goto nort2; |
| 1058 | RCU_INIT_POINTER(rt2->rt_dev, lo); | 1074 | RCU_INIT_POINTER(rt2->rt_dev, lo); |
| 1059 | rt2->rt_protocol = RTPROT_KERNEL; | 1075 | rt2->rt_protocol = RTPROT_KERNEL; |
| 1076 | rt2->rt_payload_type = MPT_IPV6; | ||
| 1060 | rt2->rt_via_table = NEIGH_LINK_TABLE; | 1077 | rt2->rt_via_table = NEIGH_LINK_TABLE; |
| 1061 | memcpy(rt2->rt_via, lo->dev_addr, lo->addr_len); | 1078 | memcpy(rt2->rt_via, lo->dev_addr, lo->addr_len); |
| 1062 | } | 1079 | } |
