return tnl_vport_to_vport(tnl_vport_table_cast(tbl_node));
}
-static inline void ecn_decapsulate(struct sk_buff *skb)
+static void ecn_decapsulate(struct sk_buff *skb, u8 tos)
{
- /* This is accessing the outer IP header of the tunnel, which we've
- * already validated to be OK. skb->data is currently set to the start
- * of the inner Ethernet header, and we've validated ETH_HLEN.
- */
- if (unlikely(INET_ECN_is_ce(ip_hdr(skb)->tos))) {
+ if (unlikely(INET_ECN_is_ce(tos))) {
__be16 protocol = skb->protocol;
skb_set_network_header(skb, ETH_HLEN);
- if (skb->protocol == htons(ETH_P_8021Q)) {
+ if (protocol == htons(ETH_P_8021Q)) {
if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN)))
return;
}
}
-/* Called with rcu_read_lock. */
-void tnl_rcv(struct vport *vport, struct sk_buff *skb)
+/**
+ * tnl_rcv - ingress point for generic tunnel code
+ *
+ * @vport: port this packet was received on
+ * @skb: received packet
+ * @tos: ToS from encapsulating IP packet, used to copy ECN bits
+ *
+ * Must be called with rcu_read_lock.
+ *
+ * Packets received by this function are in the following state:
+ * - skb->data points to the inner Ethernet header.
+ * - The inner Ethernet header is in the linear data area.
+ * - skb->csum does not include the inner Ethernet header.
+ * - The layer pointers are undefined.
+ */
+void tnl_rcv(struct vport *vport, struct sk_buff *skb, u8 tos)
{
- /* Packets received by this function are in the following state:
- * - skb->data points to the inner Ethernet header.
- * - The inner Ethernet header is in the linear data area.
- * - skb->csum does not include the inner Ethernet header.
- * - The layer pointers point at the outer headers.
- */
+ struct ethhdr *eh;
- struct ethhdr *eh = (struct ethhdr *)skb->data;
+ skb_reset_mac_header(skb);
+ eh = eth_hdr(skb);
if (likely(ntohs(eh->h_proto) >= 1536))
skb->protocol = eh->h_proto;
skb_clear_rxhash(skb);
secpath_reset(skb);
- ecn_decapsulate(skb);
+ ecn_decapsulate(skb, tos);
compute_ip_summed(skb, false);
vlan_set_tci(skb, 0);
iph->saddr = rt->rt_src;
iph->ttl = mutable->ttl;
if (!iph->ttl)
- iph->ttl = dst_metric(&rt_dst(rt), RTAX_HOPLIMIT);
+ iph->ttl = ip4_dst_hoplimit(&rt_dst(rt));
tnl_vport->tnl_ops->build_header(vport, mutable, iph + 1);
}
const struct tnl_mutable_config *mutable)
{
int sent_len;
- int err;
sent_len = 0;
while (skb) {
struct sk_buff *next = skb->next;
int frag_len = skb->len - mutable->tunnel_hlen;
+ int err;
skb->next = NULL;
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
err = ip_local_out(skb);
- if (likely(net_xmit_eval(err) == 0))
- sent_len += frag_len;
- else {
- skb = next;
- goto free_frags;
- }
-
skb = next;
+ if (unlikely(net_xmit_eval(err)))
+ goto free_frags;
+ sent_len += frag_len;
}
return sent_len;
/* TTL */
ttl = mutable->ttl;
if (!ttl)
- ttl = dst_metric(&rt_dst(rt), RTAX_HOPLIMIT);
+ ttl = ip4_dst_hoplimit(&rt_dst(rt));
if (mutable->flags & TNL_F_TTL_INHERIT) {
if (skb->protocol == htons(ETH_P_IP))
error_free:
tnl_free_linked_skbs(skb);
error:
- dst_release(unattached_dst);
vport_record_error(vport, err);
out:
+ dst_release(unattached_dst);
return sent_len;
}
if (a[ODP_TUNNEL_ATTR_TTL])
mutable->ttl = nla_get_u8(a[ODP_TUNNEL_ATTR_TTL]);
- mutable->tunnel_hlen = tnl_ops->hdr_len(mutable);
- if (mutable->tunnel_hlen < 0)
- return mutable->tunnel_hlen;
-
- mutable->tunnel_hlen += sizeof(struct iphdr);
-
mutable->tunnel_type = tnl_ops->tunnel_type;
if (!a[ODP_TUNNEL_ATTR_IN_KEY]) {
mutable->tunnel_type |= TNL_T_KEY_MATCH;
else
mutable->out_key = nla_get_be64(a[ODP_TUNNEL_ATTR_OUT_KEY]);
+ mutable->tunnel_hlen = tnl_ops->hdr_len(mutable);
+ if (mutable->tunnel_hlen < 0)
+ return mutable->tunnel_hlen;
+
+ mutable->tunnel_hlen += sizeof(struct iphdr);
+
old_vport = tnl_find_port(mutable->saddr, mutable->daddr,
mutable->in_key, mutable->tunnel_type,
&old_mutable);
void tnl_free_linked_skbs(struct sk_buff *skb)
{
- if (unlikely(!skb))
- return;
-
while (skb) {
struct sk_buff *next = skb->next;
kfree_skb(skb);