~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/seg6.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /net/ipv6/seg6.c (Version linux-6.12-rc7) and /net/ipv6/seg6.c (Version linux-6.6.58)


** Warning: Cannot open xref database.

  1 // SPDX-License-Identifier: GPL-2.0-or-later        1 
  2 /*                                                
  3  *  SR-IPv6 implementation                        
  4  *                                                
  5  *  Author:                                       
  6  *  David Lebrun <david.lebrun@uclouvain.be>      
  7  */                                               
  8                                                   
  9 #include <linux/errno.h>                          
 10 #include <linux/types.h>                          
 11 #include <linux/socket.h>                         
 12 #include <linux/net.h>                            
 13 #include <linux/in6.h>                            
 14 #include <linux/slab.h>                           
 15 #include <linux/rhashtable.h>                     
 16                                                   
 17 #include <net/ipv6.h>                             
 18 #include <net/protocol.h>                         
 19                                                   
 20 #include <net/seg6.h>                             
 21 #include <net/genetlink.h>                        
 22 #include <linux/seg6.h>                           
 23 #include <linux/seg6_genl.h>                      
 24 #include <net/seg6_hmac.h>                        
 25                                                   
 26 bool seg6_validate_srh(struct ipv6_sr_hdr *srh    
 27 {                                                 
 28         unsigned int tlv_offset;                  
 29         int max_last_entry;                       
 30         int trailing;                             
 31                                                   
 32         if (srh->type != IPV6_SRCRT_TYPE_4)       
 33                 return false;                     
 34                                                   
 35         if (((srh->hdrlen + 1) << 3) != len)      
 36                 return false;                     
 37                                                   
 38         if (!reduced && srh->segments_left > s    
 39                 return false;                     
 40         } else {                                  
 41                 max_last_entry = (srh->hdrlen     
 42                                                   
 43                 if (srh->first_segment > max_l    
 44                         return false;             
 45                                                   
 46                 if (srh->segments_left > srh->    
 47                         return false;             
 48         }                                         
 49                                                   
 50         tlv_offset = sizeof(*srh) + ((srh->fir    
 51                                                   
 52         trailing = len - tlv_offset;              
 53         if (trailing < 0)                         
 54                 return false;                     
 55                                                   
 56         while (trailing) {                        
 57                 struct sr6_tlv *tlv;              
 58                 unsigned int tlv_len;             
 59                                                   
 60                 if (trailing < sizeof(*tlv))      
 61                         return false;             
 62                                                   
 63                 tlv = (struct sr6_tlv *)((unsi    
 64                 tlv_len = sizeof(*tlv) + tlv->    
 65                                                   
 66                 trailing -= tlv_len;              
 67                 if (trailing < 0)                 
 68                         return false;             
 69                                                   
 70                 tlv_offset += tlv_len;            
 71         }                                         
 72                                                   
 73         return true;                              
 74 }                                                 
 75                                                   
 76 struct ipv6_sr_hdr *seg6_get_srh(struct sk_buf    
 77 {                                                 
 78         struct ipv6_sr_hdr *srh;                  
 79         int len, srhoff = 0;                      
 80                                                   
 81         if (ipv6_find_hdr(skb, &srhoff, IPPROT    
 82                 return NULL;                      
 83                                                   
 84         if (!pskb_may_pull(skb, srhoff + sizeo    
 85                 return NULL;                      
 86                                                   
 87         srh = (struct ipv6_sr_hdr *)(skb->data    
 88                                                   
 89         len = (srh->hdrlen + 1) << 3;             
 90                                                   
 91         if (!pskb_may_pull(skb, srhoff + len))    
 92                 return NULL;                      
 93                                                   
 94         /* note that pskb_may_pull may change     
 95          * for this reason it is necessary to     
 96          */                                       
 97         srh = (struct ipv6_sr_hdr *)(skb->data    
 98                                                   
 99         if (!seg6_validate_srh(srh, len, true)    
100                 return NULL;                      
101                                                   
102         return srh;                               
103 }                                                 
104                                                   
105 /* Determine if an ICMP invoking packet contai    
106  * header.  If it does, extract the offset to     
107  * address, which is in the first segment addr    
108  */                                               
109 void seg6_icmp_srh(struct sk_buff *skb, struct    
110 {                                                 
111         __u16 network_header = skb->network_he    
112         struct ipv6_sr_hdr *srh;                  
113                                                   
114         /* Update network header to point to t    
115          * inside the ICMP packet, so we can u    
116          * helper.                                
117          */                                       
118         skb_reset_network_header(skb);            
119                                                   
120         srh = seg6_get_srh(skb, 0);               
121         if (!srh)                                 
122                 goto out;                         
123                                                   
124         if (srh->type != IPV6_SRCRT_TYPE_4)       
125                 goto out;                         
126                                                   
127         opt->flags |= IP6SKB_SEG6;                
128         opt->srhoff = (unsigned char *)srh - s    
129                                                   
130 out:                                              
131         /* Restore the network header back to     
132         skb->network_header = network_header;     
133 }                                                 
134                                                   
135 static struct genl_family seg6_genl_family;       
136                                                   
137 static const struct nla_policy seg6_genl_polic    
138         [SEG6_ATTR_DST]                           
139                 .len = sizeof(struct in6_addr)    
140         [SEG6_ATTR_DSTLEN]                        
141         [SEG6_ATTR_HMACKEYID]           = { .t    
142         [SEG6_ATTR_SECRET]                        
143         [SEG6_ATTR_SECRETLEN]           = { .t    
144         [SEG6_ATTR_ALGID]                         
145         [SEG6_ATTR_HMACINFO]            = { .t    
146 };                                                
147                                                   
148 #ifdef CONFIG_IPV6_SEG6_HMAC                      
149                                                   
150 static int seg6_genl_sethmac(struct sk_buff *s    
151 {                                                 
152         struct net *net = genl_info_net(info);    
153         struct seg6_pernet_data *sdata;           
154         struct seg6_hmac_info *hinfo;             
155         u32 hmackeyid;                            
156         char *secret;                             
157         int err = 0;                              
158         u8 algid;                                 
159         u8 slen;                                  
160                                                   
161         sdata = seg6_pernet(net);                 
162                                                   
163         if (!info->attrs[SEG6_ATTR_HMACKEYID]     
164             !info->attrs[SEG6_ATTR_SECRETLEN]     
165             !info->attrs[SEG6_ATTR_ALGID])        
166                 return -EINVAL;                   
167                                                   
168         hmackeyid = nla_get_u32(info->attrs[SE    
169         slen = nla_get_u8(info->attrs[SEG6_ATT    
170         algid = nla_get_u8(info->attrs[SEG6_AT    
171                                                   
172         if (hmackeyid == 0)                       
173                 return -EINVAL;                   
174                                                   
175         if (slen > SEG6_HMAC_SECRET_LEN)          
176                 return -EINVAL;                   
177                                                   
178         mutex_lock(&sdata->lock);                 
179         hinfo = seg6_hmac_info_lookup(net, hma    
180                                                   
181         if (!slen) {                              
182                 err = seg6_hmac_info_del(net,     
183                                                   
184                 goto out_unlock;                  
185         }                                         
186                                                   
187         if (!info->attrs[SEG6_ATTR_SECRET]) {     
188                 err = -EINVAL;                    
189                 goto out_unlock;                  
190         }                                         
191                                                   
192         if (slen > nla_len(info->attrs[SEG6_AT    
193                 err = -EINVAL;                    
194                 goto out_unlock;                  
195         }                                         
196                                                   
197         if (hinfo) {                              
198                 err = seg6_hmac_info_del(net,     
199                 if (err)                          
200                         goto out_unlock;          
201         }                                         
202                                                   
203         secret = (char *)nla_data(info->attrs[    
204                                                   
205         hinfo = kzalloc(sizeof(*hinfo), GFP_KE    
206         if (!hinfo) {                             
207                 err = -ENOMEM;                    
208                 goto out_unlock;                  
209         }                                         
210                                                   
211         memcpy(hinfo->secret, secret, slen);      
212         hinfo->slen = slen;                       
213         hinfo->alg_id = algid;                    
214         hinfo->hmackeyid = hmackeyid;             
215                                                   
216         err = seg6_hmac_info_add(net, hmackeyi    
217         if (err)                                  
218                 kfree(hinfo);                     
219                                                   
220 out_unlock:                                       
221         mutex_unlock(&sdata->lock);               
222         return err;                               
223 }                                                 
224                                                   
225 #else                                             
226                                                   
227 static int seg6_genl_sethmac(struct sk_buff *s    
228 {                                                 
229         return -ENOTSUPP;                         
230 }                                                 
231                                                   
232 #endif                                            
233                                                   
234 static int seg6_genl_set_tunsrc(struct sk_buff    
235 {                                                 
236         struct net *net = genl_info_net(info);    
237         struct in6_addr *val, *t_old, *t_new;     
238         struct seg6_pernet_data *sdata;           
239                                                   
240         sdata = seg6_pernet(net);                 
241                                                   
242         if (!info->attrs[SEG6_ATTR_DST])          
243                 return -EINVAL;                   
244                                                   
245         val = nla_data(info->attrs[SEG6_ATTR_D    
246         t_new = kmemdup(val, sizeof(*val), GFP    
247         if (!t_new)                               
248                 return -ENOMEM;                   
249                                                   
250         mutex_lock(&sdata->lock);                 
251                                                   
252         t_old = sdata->tun_src;                   
253         rcu_assign_pointer(sdata->tun_src, t_n    
254                                                   
255         mutex_unlock(&sdata->lock);               
256                                                   
257         synchronize_net();                        
258         kfree(t_old);                             
259                                                   
260         return 0;                                 
261 }                                                 
262                                                   
263 static int seg6_genl_get_tunsrc(struct sk_buff    
264 {                                                 
265         struct net *net = genl_info_net(info);    
266         struct in6_addr *tun_src;                 
267         struct sk_buff *msg;                      
268         void *hdr;                                
269                                                   
270         msg = genlmsg_new(NLMSG_DEFAULT_SIZE,     
271         if (!msg)                                 
272                 return -ENOMEM;                   
273                                                   
274         hdr = genlmsg_put(msg, info->snd_porti    
275                           &seg6_genl_family, 0    
276         if (!hdr)                                 
277                 goto free_msg;                    
278                                                   
279         rcu_read_lock();                          
280         tun_src = rcu_dereference(seg6_pernet(    
281                                                   
282         if (nla_put(msg, SEG6_ATTR_DST, sizeof    
283                 goto nla_put_failure;             
284                                                   
285         rcu_read_unlock();                        
286                                                   
287         genlmsg_end(msg, hdr);                    
288         return genlmsg_reply(msg, info);          
289                                                   
290 nla_put_failure:                                  
291         rcu_read_unlock();                        
292 free_msg:                                         
293         nlmsg_free(msg);                          
294         return -ENOMEM;                           
295 }                                                 
296                                                   
297 #ifdef CONFIG_IPV6_SEG6_HMAC                      
298                                                   
299 static int __seg6_hmac_fill_info(struct seg6_h    
300                                  struct sk_buf    
301 {                                                 
302         if (nla_put_u32(msg, SEG6_ATTR_HMACKEY    
303             nla_put_u8(msg, SEG6_ATTR_SECRETLE    
304             nla_put(msg, SEG6_ATTR_SECRET, hin    
305             nla_put_u8(msg, SEG6_ATTR_ALGID, h    
306                 return -1;                        
307                                                   
308         return 0;                                 
309 }                                                 
310                                                   
311 static int __seg6_genl_dumphmac_element(struct    
312                                         u32 po    
313                                         struct    
314 {                                                 
315         void *hdr;                                
316                                                   
317         hdr = genlmsg_put(skb, portid, seq, &s    
318         if (!hdr)                                 
319                 return -ENOMEM;                   
320                                                   
321         if (__seg6_hmac_fill_info(hinfo, skb)     
322                 goto nla_put_failure;             
323                                                   
324         genlmsg_end(skb, hdr);                    
325         return 0;                                 
326                                                   
327 nla_put_failure:                                  
328         genlmsg_cancel(skb, hdr);                 
329         return -EMSGSIZE;                         
330 }                                                 
331                                                   
332 static int seg6_genl_dumphmac_start(struct net    
333 {                                                 
334         struct net *net = sock_net(cb->skb->sk    
335         struct seg6_pernet_data *sdata;           
336         struct rhashtable_iter *iter;             
337                                                   
338         sdata = seg6_pernet(net);                 
339         iter = (struct rhashtable_iter *)cb->a    
340                                                   
341         if (!iter) {                              
342                 iter = kmalloc(sizeof(*iter),     
343                 if (!iter)                        
344                         return -ENOMEM;           
345                                                   
346                 cb->args[0] = (long)iter;         
347         }                                         
348                                                   
349         rhashtable_walk_enter(&sdata->hmac_inf    
350                                                   
351         return 0;                                 
352 }                                                 
353                                                   
354 static int seg6_genl_dumphmac_done(struct netl    
355 {                                                 
356         struct rhashtable_iter *iter = (struct    
357                                                   
358         rhashtable_walk_exit(iter);               
359                                                   
360         kfree(iter);                              
361                                                   
362         return 0;                                 
363 }                                                 
364                                                   
365 static int seg6_genl_dumphmac(struct sk_buff *    
366 {                                                 
367         struct rhashtable_iter *iter = (struct    
368         struct seg6_hmac_info *hinfo;             
369         int ret;                                  
370                                                   
371         rhashtable_walk_start(iter);              
372                                                   
373         for (;;) {                                
374                 hinfo = rhashtable_walk_next(i    
375                                                   
376                 if (IS_ERR(hinfo)) {              
377                         if (PTR_ERR(hinfo) ==     
378                                 continue;         
379                         ret = PTR_ERR(hinfo);     
380                         goto done;                
381                 } else if (!hinfo) {              
382                         break;                    
383                 }                                 
384                                                   
385                 ret = __seg6_genl_dumphmac_ele    
386                                                   
387                                                   
388                                                   
389                                                   
390                 if (ret)                          
391                         goto done;                
392         }                                         
393                                                   
394         ret = skb->len;                           
395                                                   
396 done:                                             
397         rhashtable_walk_stop(iter);               
398         return ret;                               
399 }                                                 
400                                                   
401 #else                                             
402                                                   
403 static int seg6_genl_dumphmac_start(struct net    
404 {                                                 
405         return 0;                                 
406 }                                                 
407                                                   
408 static int seg6_genl_dumphmac_done(struct netl    
409 {                                                 
410         return 0;                                 
411 }                                                 
412                                                   
413 static int seg6_genl_dumphmac(struct sk_buff *    
414 {                                                 
415         return -ENOTSUPP;                         
416 }                                                 
417                                                   
418 #endif                                            
419                                                   
420 static int __net_init seg6_net_init(struct net    
421 {                                                 
422         struct seg6_pernet_data *sdata;           
423                                                   
424         sdata = kzalloc(sizeof(*sdata), GFP_KE    
425         if (!sdata)                               
426                 return -ENOMEM;                   
427                                                   
428         mutex_init(&sdata->lock);                 
429                                                   
430         sdata->tun_src = kzalloc(sizeof(*sdata    
431         if (!sdata->tun_src) {                    
432                 kfree(sdata);                     
433                 return -ENOMEM;                   
434         }                                         
435                                                   
436         net->ipv6.seg6_data = sdata;              
437                                                   
438         if (seg6_hmac_net_init(net)) {            
439                 kfree(rcu_dereference_raw(sdat    
440                 kfree(sdata);                     
441                 return -ENOMEM;                   
442         }                                         
443                                                   
444         return 0;                                 
445 }                                                 
446                                                   
447 static void __net_exit seg6_net_exit(struct ne    
448 {                                                 
449         struct seg6_pernet_data *sdata = seg6_    
450                                                   
451         seg6_hmac_net_exit(net);                  
452                                                   
453         kfree(rcu_dereference_raw(sdata->tun_s    
454         kfree(sdata);                             
455 }                                                 
456                                                   
457 static struct pernet_operations ip6_segments_o    
458         .init = seg6_net_init,                    
459         .exit = seg6_net_exit,                    
460 };                                                
461                                                   
462 static const struct genl_ops seg6_genl_ops[] =    
463         {                                         
464                 .cmd    = SEG6_CMD_SETHMAC,       
465                 .validate = GENL_DONT_VALIDATE    
466                 .doit   = seg6_genl_sethmac,      
467                 .flags  = GENL_ADMIN_PERM,        
468         },                                        
469         {                                         
470                 .cmd    = SEG6_CMD_DUMPHMAC,      
471                 .validate = GENL_DONT_VALIDATE    
472                 .start  = seg6_genl_dumphmac_s    
473                 .dumpit = seg6_genl_dumphmac,     
474                 .done   = seg6_genl_dumphmac_d    
475                 .flags  = GENL_ADMIN_PERM,        
476         },                                        
477         {                                         
478                 .cmd    = SEG6_CMD_SET_TUNSRC,    
479                 .validate = GENL_DONT_VALIDATE    
480                 .doit   = seg6_genl_set_tunsrc    
481                 .flags  = GENL_ADMIN_PERM,        
482         },                                        
483         {                                         
484                 .cmd    = SEG6_CMD_GET_TUNSRC,    
485                 .validate = GENL_DONT_VALIDATE    
486                 .doit   = seg6_genl_get_tunsrc    
487                 .flags  = GENL_ADMIN_PERM,        
488         },                                        
489 };                                                
490                                                   
491 static struct genl_family seg6_genl_family __r    
492         .hdrsize        = 0,                      
493         .name           = SEG6_GENL_NAME,         
494         .version        = SEG6_GENL_VERSION,      
495         .maxattr        = SEG6_ATTR_MAX,          
496         .policy = seg6_genl_policy,               
497         .netnsok        = true,                   
498         .parallel_ops   = true,                   
499         .ops            = seg6_genl_ops,          
500         .n_ops          = ARRAY_SIZE(seg6_genl    
501         .resv_start_op  = SEG6_CMD_GET_TUNSRC     
502         .module         = THIS_MODULE,            
503 };                                                
504                                                   
505 int __init seg6_init(void)                        
506 {                                                 
507         int err;                                  
508                                                   
509         err = register_pernet_subsys(&ip6_segm    
510         if (err)                                  
511                 goto out;                         
512                                                   
513         err = genl_register_family(&seg6_genl_    
514         if (err)                                  
515                 goto out_unregister_pernet;       
516                                                   
517         err = seg6_iptunnel_init();               
518         if (err)                                  
519                 goto out_unregister_genl;         
520                                                   
521         err = seg6_local_init();                  
522         if (err)                                  
523                 goto out_unregister_iptun;        
524                                                   
525         err = seg6_hmac_init();                   
526         if (err)                                  
527                 goto out_unregister_seg6;         
528                                                   
529         pr_info("Segment Routing with IPv6\n")    
530                                                   
531 out:                                              
532         return err;                               
533 out_unregister_seg6:                              
534         seg6_local_exit();                        
535 out_unregister_iptun:                             
536         seg6_iptunnel_exit();                     
537 out_unregister_genl:                              
538         genl_unregister_family(&seg6_genl_fami    
539 out_unregister_pernet:                            
540         unregister_pernet_subsys(&ip6_segments    
541         goto out;                                 
542 }                                                 
543                                                   
544 void seg6_exit(void)                              
545 {                                                 
546         seg6_hmac_exit();                         
547         seg6_local_exit();                        
548         seg6_iptunnel_exit();                     
549         genl_unregister_family(&seg6_genl_fami    
550         unregister_pernet_subsys(&ip6_segments    
551 }                                                 
552                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php