162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef MPLS_INTERNAL_H 362306a36Sopenharmony_ci#define MPLS_INTERNAL_H 462306a36Sopenharmony_ci#include <net/mpls.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* put a reasonable limit on the number of labels 762306a36Sopenharmony_ci * we will accept from userspace 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#define MAX_NEW_LABELS 30 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistruct mpls_entry_decoded { 1262306a36Sopenharmony_ci u32 label; 1362306a36Sopenharmony_ci u8 ttl; 1462306a36Sopenharmony_ci u8 tc; 1562306a36Sopenharmony_ci u8 bos; 1662306a36Sopenharmony_ci}; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct mpls_pcpu_stats { 1962306a36Sopenharmony_ci struct mpls_link_stats stats; 2062306a36Sopenharmony_ci struct u64_stats_sync syncp; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct mpls_dev { 2462306a36Sopenharmony_ci int input_enabled; 2562306a36Sopenharmony_ci struct net_device *dev; 2662306a36Sopenharmony_ci struct mpls_pcpu_stats __percpu *stats; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci struct ctl_table_header *sysctl; 2962306a36Sopenharmony_ci struct rcu_head rcu; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#if BITS_PER_LONG == 32 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define MPLS_INC_STATS_LEN(mdev, len, pkts_field, bytes_field) \ 3562306a36Sopenharmony_ci do { \ 3662306a36Sopenharmony_ci __typeof__(*(mdev)->stats) *ptr = \ 3762306a36Sopenharmony_ci raw_cpu_ptr((mdev)->stats); \ 3862306a36Sopenharmony_ci local_bh_disable(); \ 3962306a36Sopenharmony_ci u64_stats_update_begin(&ptr->syncp); \ 4062306a36Sopenharmony_ci ptr->stats.pkts_field++; \ 4162306a36Sopenharmony_ci ptr->stats.bytes_field += (len); \ 4262306a36Sopenharmony_ci u64_stats_update_end(&ptr->syncp); \ 4362306a36Sopenharmony_ci local_bh_enable(); \ 4462306a36Sopenharmony_ci } while (0) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define MPLS_INC_STATS(mdev, field) \ 4762306a36Sopenharmony_ci do { \ 4862306a36Sopenharmony_ci __typeof__(*(mdev)->stats) *ptr = \ 4962306a36Sopenharmony_ci raw_cpu_ptr((mdev)->stats); \ 5062306a36Sopenharmony_ci local_bh_disable(); \ 5162306a36Sopenharmony_ci u64_stats_update_begin(&ptr->syncp); \ 5262306a36Sopenharmony_ci ptr->stats.field++; \ 5362306a36Sopenharmony_ci u64_stats_update_end(&ptr->syncp); \ 5462306a36Sopenharmony_ci local_bh_enable(); \ 5562306a36Sopenharmony_ci } while (0) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#else 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define MPLS_INC_STATS_LEN(mdev, len, pkts_field, bytes_field) \ 6062306a36Sopenharmony_ci do { \ 6162306a36Sopenharmony_ci this_cpu_inc((mdev)->stats->stats.pkts_field); \ 6262306a36Sopenharmony_ci this_cpu_add((mdev)->stats->stats.bytes_field, (len)); \ 6362306a36Sopenharmony_ci } while (0) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define MPLS_INC_STATS(mdev, field) \ 6662306a36Sopenharmony_ci this_cpu_inc((mdev)->stats->stats.field) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#endif 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistruct sk_buff; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define LABEL_NOT_SPECIFIED (1 << 20) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* This maximum ha length copied from the definition of struct neighbour */ 7562306a36Sopenharmony_ci#define VIA_ALEN_ALIGN sizeof(unsigned long) 7662306a36Sopenharmony_ci#define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, VIA_ALEN_ALIGN)) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cienum mpls_payload_type { 7962306a36Sopenharmony_ci MPT_UNSPEC, /* IPv4 or IPv6 */ 8062306a36Sopenharmony_ci MPT_IPV4 = 4, 8162306a36Sopenharmony_ci MPT_IPV6 = 6, 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Other types not implemented: 8462306a36Sopenharmony_ci * - Pseudo-wire with or without control word (RFC4385) 8562306a36Sopenharmony_ci * - GAL (RFC5586) 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistruct mpls_nh { /* next hop label forwarding entry */ 9062306a36Sopenharmony_ci struct net_device *nh_dev; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* nh_flags is accessed under RCU in the packet path; it is 9362306a36Sopenharmony_ci * modified handling netdev events with rtnl lock held 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci unsigned int nh_flags; 9662306a36Sopenharmony_ci u8 nh_labels; 9762306a36Sopenharmony_ci u8 nh_via_alen; 9862306a36Sopenharmony_ci u8 nh_via_table; 9962306a36Sopenharmony_ci u8 nh_reserved1; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci u32 nh_label[]; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* offset of via from beginning of mpls_nh */ 10562306a36Sopenharmony_ci#define MPLS_NH_VIA_OFF(num_labels) \ 10662306a36Sopenharmony_ci ALIGN(sizeof(struct mpls_nh) + (num_labels) * sizeof(u32), \ 10762306a36Sopenharmony_ci VIA_ALEN_ALIGN) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* all nexthops within a route have the same size based on the 11062306a36Sopenharmony_ci * max number of labels and max via length across all nexthops 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci#define MPLS_NH_SIZE(num_labels, max_via_alen) \ 11362306a36Sopenharmony_ci (MPLS_NH_VIA_OFF((num_labels)) + \ 11462306a36Sopenharmony_ci ALIGN((max_via_alen), VIA_ALEN_ALIGN)) 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cienum mpls_ttl_propagation { 11762306a36Sopenharmony_ci MPLS_TTL_PROP_DEFAULT, 11862306a36Sopenharmony_ci MPLS_TTL_PROP_ENABLED, 11962306a36Sopenharmony_ci MPLS_TTL_PROP_DISABLED, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* The route, nexthops and vias are stored together in the same memory 12362306a36Sopenharmony_ci * block: 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * +----------------------+ 12662306a36Sopenharmony_ci * | mpls_route | 12762306a36Sopenharmony_ci * +----------------------+ 12862306a36Sopenharmony_ci * | mpls_nh 0 | 12962306a36Sopenharmony_ci * +----------------------+ 13062306a36Sopenharmony_ci * | alignment padding | 4 bytes for odd number of labels 13162306a36Sopenharmony_ci * +----------------------+ 13262306a36Sopenharmony_ci * | via[rt_max_alen] 0 | 13362306a36Sopenharmony_ci * +----------------------+ 13462306a36Sopenharmony_ci * | alignment padding | via's aligned on sizeof(unsigned long) 13562306a36Sopenharmony_ci * +----------------------+ 13662306a36Sopenharmony_ci * | ... | 13762306a36Sopenharmony_ci * +----------------------+ 13862306a36Sopenharmony_ci * | mpls_nh n-1 | 13962306a36Sopenharmony_ci * +----------------------+ 14062306a36Sopenharmony_ci * | via[rt_max_alen] n-1 | 14162306a36Sopenharmony_ci * +----------------------+ 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_cistruct mpls_route { /* next hop label forwarding entry */ 14462306a36Sopenharmony_ci struct rcu_head rt_rcu; 14562306a36Sopenharmony_ci u8 rt_protocol; 14662306a36Sopenharmony_ci u8 rt_payload_type; 14762306a36Sopenharmony_ci u8 rt_max_alen; 14862306a36Sopenharmony_ci u8 rt_ttl_propagate; 14962306a36Sopenharmony_ci u8 rt_nhn; 15062306a36Sopenharmony_ci /* rt_nhn_alive is accessed under RCU in the packet path; it 15162306a36Sopenharmony_ci * is modified handling netdev events with rtnl lock held 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci u8 rt_nhn_alive; 15462306a36Sopenharmony_ci u8 rt_nh_size; 15562306a36Sopenharmony_ci u8 rt_via_offset; 15662306a36Sopenharmony_ci u8 rt_reserved1; 15762306a36Sopenharmony_ci struct mpls_nh rt_nh[]; 15862306a36Sopenharmony_ci}; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#define for_nexthops(rt) { \ 16162306a36Sopenharmony_ci int nhsel; const struct mpls_nh *nh; \ 16262306a36Sopenharmony_ci for (nhsel = 0, nh = (rt)->rt_nh; \ 16362306a36Sopenharmony_ci nhsel < (rt)->rt_nhn; \ 16462306a36Sopenharmony_ci nh = (void *)nh + (rt)->rt_nh_size, nhsel++) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define change_nexthops(rt) { \ 16762306a36Sopenharmony_ci int nhsel; struct mpls_nh *nh; \ 16862306a36Sopenharmony_ci for (nhsel = 0, nh = (rt)->rt_nh; \ 16962306a36Sopenharmony_ci nhsel < (rt)->rt_nhn; \ 17062306a36Sopenharmony_ci nh = (void *)nh + (rt)->rt_nh_size, nhsel++) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#define endfor_nexthops(rt) } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline struct mpls_entry_decoded mpls_entry_decode(struct mpls_shim_hdr *hdr) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct mpls_entry_decoded result; 17762306a36Sopenharmony_ci unsigned entry = be32_to_cpu(hdr->label_stack_entry); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci result.label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT; 18062306a36Sopenharmony_ci result.ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT; 18162306a36Sopenharmony_ci result.tc = (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT; 18262306a36Sopenharmony_ci result.bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return result; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic inline struct mpls_dev *mpls_dev_get(const struct net_device *dev) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci return rcu_dereference_rtnl(dev->mpls_ptr); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciint nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels, 19362306a36Sopenharmony_ci const u32 label[]); 19462306a36Sopenharmony_ciint nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels, 19562306a36Sopenharmony_ci u32 label[], struct netlink_ext_ack *extack); 19662306a36Sopenharmony_cibool mpls_output_possible(const struct net_device *dev); 19762306a36Sopenharmony_ciunsigned int mpls_dev_mtu(const struct net_device *dev); 19862306a36Sopenharmony_cibool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu); 19962306a36Sopenharmony_civoid mpls_stats_inc_outucastpkts(struct net_device *dev, 20062306a36Sopenharmony_ci const struct sk_buff *skb); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#endif /* MPLS_INTERNAL_H */ 203